New Swagger based API docs available
Introduction
FinTecSystems offers easy to use and easy to integrate client and server-side APIs based on our XS2A platform.
The API provides an interface for connecting and extracting online banking account information to meet your individual business requirements. We like to call it the “access to the account” concept.
API
Authentication
https://api.xs2a.com/
Default API endpoint
You can create and manage API keys from your account. Multiple API keys can be active at the same time.
Authentication to the API uses HTTP Basic Auth. Provide api
as username and your API key as password.
Endpoints are only available via HTTPS. Plain HTTP requests will not be processed.
Please be aware of the different modes for API keys. An API key in mode Test
is not allowed to
access Live
transactions. Live
API keys are not able to access data made from test transactions.
Should the authentication fail, you will received a 401 HTTP error code with a corresponding error message, see also Error messages.
This example uses a GET request to call the URL. The username
api
is always used for API authentication. Password is your generated API key.
curl -X GET --user api:<your-api-key> https://api.xs2a.com/v1/version
GET /v1/version HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
The above command returns JSON structured like this:
{
"version": "2015-11-13"
}
We mostly use cURL in our examples but you can also use POST requests with JSON body to communicate with our API.
Please make sure to include the HTTP header Content-Type: application/json
with your JSON body, if you decide to use
JSON for your POST data instead of URL encoded data.
Error Messages
With all error codes >400 you will receive an additional error message in the response body.
{
"code": "401",
"message": "Invalid credentials."
}
The HTTP status code 422 returns a special object. The error messages are returned corresponding to the field:
{
"code": 422,
"message": "Validation failed",
"errors": {
"direction": [
"The selected direction is invalid."
],
"per_page": [
"The per page must be an integer."
]
}
}
The API uses HTTP status codes for error messages:
HTTP Status Code | Description |
---|---|
200 | Request successful processed |
401 | Authentication failed API key missing or not valid |
403 | Forbidden Access blocked |
404 | Not found The requested object does not exist on the server |
410* | The object has been deleted intentionally |
422 | Validation failed Something is wrong with the user input |
500 | An internal server problem occurred |
* Please note that to comply with our privacy policy we only keep transaction data for 30 days. The transaction data will not be available after this period.
Pagination
{
"total": 15,
"per_page": 15,
"current_page": 1,
"last_page": 8,
"from": 1,
"to": 15,
"data": [
// ... user data ...
]
}
Most calls which return a list like data structure allow pagination.
Explanation of response fields:
Key | Type | Description |
---|---|---|
total | number | Total number of results. |
per_page | number | Number of objects per page. |
current_page | number | Current page. |
last_page | number | Last page, usually the total of available pages. |
from | number | Showing results from index element. |
to | number | Showing results to index element. |
data | array | An array of user data with the actual results. |
Every call that supports paging is able to use the parameters per_page
and page
.
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/events?page=1&per_page=15
GET /v1/events?page=1&per_page=15 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"total": 66,
"per_page": 15,
"current_page": 1,
"last_page": 5,
"from": 1,
"to": 15,
"data": [
{
"id": "ev_fhDFdPRtECqwOlys",
"transaction": "xv_eR08AnBz7CeBKnzp",
"type": "transaction.created",
"data": {
"account_holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"check_requested": false,
"check_amount": 0,
"check_currency_id": "EUR",
"check_passed": false,
"metadata": null,
"merchant_id": "",
"transaction": "10001-xv-zCTO-xpIT",
"testmode": "1",
"id": "xv_eR08AnBz7CeBKnzp",
"created_at": "2015-05-05 11:47:45",
"object": "xs2a_verification"
},
"testmode": "1",
"created_at": "2015-05-05 11:47:45",
"message": "Transaction xv_eR08AnBz7CeBKnzp created.",
"object": "xs2a_event"
},
]
}
Versioning
curl -X GET \
--user api:<your-api-key> \
https://api.xs2a.com/v1/version
GET /v1/version HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"version": "2015-11-13"
}
In case we make an API change, we might release a new version of the API. You can retrieve the current version by calling the version endpoint. This contains the date of the release date of the API. With every change we update the release date.
API compatibility
We consider the following changes as ‘non-breaking’ changes to the API:
- Adding a field to an object
- Introducing a new API endpoint that did not exist before
- Adding a search parameter
However we consider these examples for 'breaking’ changes:
- Changing the datatype of a field
- Removing a field from an object
- Changing the semantics of an existing field
- Changing URLs
We consider the HTML that is generated by our xs2a.js
and possibly styled
by your own application as a form of API, and also try to limit changes to
the structure and semantics of the generated markup, however we might
add certain markup in the future which is the reason why you have to include
the xs2a.css
file in your HTML.
Blacklist
The Blacklist API allows you to magage a personal blacklist of IBANs. After adding an iban to the blacklist the customer won’t be able to use it in the XS2A Wizard.
The following operations are available.
Add item
POST /v1/blacklist HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
{
"data": "EE382200221020145685"
}
Adding a blacklist entry
Use the following endpoint.
POST https://api.xs2a.com/v1/blacklist
The POST request has to include the following parameter:
Parameter | Type | Required | Description |
---|---|---|---|
data | string | Required | Valid IBAN |
Item details
GET /v1/blacklist/bl_c3nL2MafX8WdfiIM HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Getting the details of a blacklist item
Use the following endpoint.
GET https://api.xs2a.com/v1/blacklist/<id>
The
Removing an item
DELETE /v1/blacklist/bl_c3nL2MafX8WdfiIM HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Removing an item from the blacklist
Use the following endpoint.
DELETE https://api.xs2a.com/v1/blacklist/<id>
The
Response
{
"id": "bl_c3nL2MafX8WdfiIM",
"data": "EE382200221020145685",
"type": "iban"
}
Response of all the requests
The Response of the requests is an object with the following fields.
Parameter | Type | Description |
---|---|---|
id | string | Blacklist item id |
type | string | Type of the entry, in this case ‘iban’ |
data | string | IBAN |
Errors and validation errors
{
"code": 422,
"message": "Validation failed",
"errors": {
"data": [
"Duplicate entry."
]
}
}
{
"code": 404,
"message": "The requested resource was not found"
}
Validation Errors
The following errors could occur when adding, removing or selecting an item.
- 404 - The requested resource was not found
- 422 - Validation error
- The Account holder or IBAN field is required.
- Duplicate Entry
- The Account holder or IBAN must be a valid International Bank Account Number (IBAN)
Complete Blacklist
GET /v1/blacklist HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Response
{
"total": 2,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"next_page_url": null,
"prev_page_url": null,
"from": 1,
"to": 2,
"data": [
{
"id": "bl_I6oeEWMVltIS2tOt",
"data": "FR1420041010050500013M02606",
"type": "iban"
},
{
"id": "bl_4epDHJnxDwkbDKJF",
"data": "EE382200221020145685",
"type": "iban"
},
]
}
Getting a list of all blacklist items
Yout can get a list of all the blacklist items by using the following endpoint.
GET https://api.xs2a.com/v1/blacklist
The items will be wrapped in a pagination element. Read the chapter Pagination for more information.
Bankcodes
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/bankcodes?bank_code=88888888&country_id=DE
GET /v1/bankcodes?bank_code=88888888&country_id=DE HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Using BIC instead of bank code
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/bankcodes?bic=TESTDE88XXX
GET /v1/bankcodes?bic=TESTDE88XXX HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
If you are unsure whether the customer has entered a BIC or bank code use the
q
parameter:
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/bankcodes?q=TESTDE88XXX
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/bankcodes?q=88888888
GET /v1/bankcodes?q=TESTDE88XXX HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
GET /v1/bankcodes?q=88888888 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"bank_code": "88888888",
"bic": "TESTDE88XXX",
"name": "Testbank",
"short_name": "Testbank",
"zipcode": 12345,
"city": "Teststadt",
"country_id": "DE",
"xs2a_supported": true,
"testmode": true
}
XS2A might not support every bank. To help you decide whether or not you should offer a XS2A product to a customer, you can call this API endpoint to determine whether or not XS2A supports the bank code of the customer.
You will receive information about the selected bank. The field xs2a_supported
can be used to determine whether or not you should offer XS2A products to your customer.
Parameter | Type | Required | Description |
---|---|---|---|
bank_code | string | Optional | bank code of the customers bank, optionally a country_id, otherwise Germany will be assumed |
country_id | string | Optional | Two letter country code id, e.g. AT, CH, DE |
bic | string | Optional | BIC of the customers bank, no country id is necessary |
q | string | Optional | Uses the value to search for customers bank as either BIC or bank code |
The call returns a bank object, which has these properties:
Property | Type | Description |
---|---|---|
bank_code | string | bank code of the bank |
bic | string | BIC of the bank |
name | string | Name of the bank |
short_name | string | Abbreviated bank name |
zipcode | string | National ZIP code of the bank |
city | string | City |
country_id | string | Two letter country code id, e.g. AT, CH, DE |
xs2a_supported | boolean | true , if this bank is supported by XS2A |
testmode | boolean | true , if this bank is a testbank |
All bankcodes
Get all bank codes (paginated)
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/bankcodes/all
GET /v1/bankcodes/all? HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
For a paginated result of all bank-codes send an empty GET request.
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
country_id | string | Optional | DE | Two letter country code id, e.g. AT, CH, DE |
per_page | number | Optional | 15 | Items per page |
page | number | Optional | 1 | Which page to display |
The call returns a paginated list of bank objects, which have these properties:
Property | Type | Description |
---|---|---|
bank_code | string | bank code of the bank |
bic | string | BIC of the bank |
name | string | Name of the bank |
short_name | string | Abbreviated bank name |
zipcode | string | National ZIP code of the bank |
city | string | City |
country_id | string | Two letter country code id, e.g. AT, CH, DE |
xs2a_supported | boolean | true , if this bank is supported by XS2A |
testmode | boolean | true , if this bank is a testbank |
Bankcodes autocomplete
For a paginated result of bankcodes based on a query string send a GET to v1/bankcodes/autocomplete
Search for a bank code (paginated)
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/bankcodes/autocomplete?q=<search-query-here>
GET /v1/bankcodes/autocomplete?q=<search-query-here> HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
q | string | Required | Part of a bank_code, bic or bank name. | |
country_id | string | Optional | DE | Two letter country code id, e.g. AT, CH, DE |
per_page | number | Optional | 15 | Items per page. |
page | number | Optional | 1 | Which page to display. |
product | string | Optional | Limit your search to a specific product. Valid vale |
The call returns a paginated list of bank objects, which have these properties:
Property | Type | Description |
---|---|---|
bank_code | string | bank code of the bank |
bic | string | BIC of the bank |
name | string | Name of the bank |
short_name | string | Abbreviated bank name |
zipcode | string | National ZIP code of the bank |
city | string | City |
country_id | string | Two letter country code id, e.g. AT, CH, DE |
xs2a_supported | boolean | true , if this bank is supported by XS2A |
testmode | boolean | true , if this bank is a testbank |
XS2A.verify
curl -X POST -u api:<your-api-key> \
-d bank_code=88888888 \
-d country_id=DE \
-d check_amount=100 \
-d check_currency_id=EUR \
https://api.xs2a.com/v1/verifications
POST /v1/verifications HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 71
bank_code=88888888&country_id=DE&check_amount=100&check_currency_id=EUR
Request using POST with JSON
curl -X POST -u api:<your-api-key> \
-H 'Content-Type: application/json'
-d '{ "bank_code": "88888888", "country_id": "DE", "check_amount": 100, "check_currency_id": "EUR" }' \
https://api.xs2a.com/v1/verifications
POST /v1/verifications HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 100
{
"bank_code": "88888888",
"country_id": "DE",
"check_amount": 100,
"check_currency_id": "EUR"
}
Server-Response
{
"wizard_session_key": "<random-key>",
"transaction": "<internal-XS2A-ID>"
}
Example request with BIC
curl -X POST -u api:<your-api-key> \
-d bic=TESTDE88XXX \
-d check_amount=100 \
-d check_currency_id=EUR \
https://api.xs2a.com/v1/verifications
POST /v1/verifications HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 76
{
"bic": "TESTDE88XXX",
"check_amount": 100,
"check_currency_id": "EUR"
}
Example request with metadata
curl -X POST -u api:<your-api-key> \
-d bic=TESTDE88XXX \
-d check_amount=100 \
-d check_currency_id=EUR \
-d metadata[custid]=4711 \
-d metadata[orderid]=12345 \
https://api.xs2a.com/v1/verifications
POST /v1/verifications HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 165
{
"bic": "TESTDE88XXX",
"check_amount": "100",
"check_currency_id": "EUR",
"metadata": {
"custid": "4711",
"orderid": "12345"
}
}
XS2A.verify allows you to collect and validate a bank connection. Optionally you can check the account balance/coverage against a given amount.
To create an XS2A.verify object and receive a Wizard session key use the endpoint
POST https://api.xs2a.com/v1/verifications
Please make sure to include the HTTP header Content-Type: application/json
with your JSON body, if you decide to use
JSON for your POST data instead of URL encoded data.
The POST request may include the following parameters:
Parameter | Type | Required | Description |
---|---|---|---|
bank_code | number | Optional | bank code of the customers bank, requires also parameter country_id. If supplied the step/page for entering a bank code will be skipped. |
country_id | string | Optional | Two letter country code id, e.g. AT, CH, DE |
account_number | string | Optional | (national) account number of the customer |
iban | string | Optional | IBAN of the customers account |
bic | string | Optional | BIC of the customers account |
check_amount | number | Optional | Account balance amount to be checked against |
check_currency_id | string | Optional | Currency id of check_amount, e.g. EUR |
metadata | array | Optional | An array of data which will be passed back to your application |
merchant_id | string | Optional | The internal ID of your merchant, if any. |
language | string | Optional | The initial language. May be en or de . |
- account_number - The (national) account number of the customer. Is the account number valid, an IBAN will be calculated using the bank code and the account number. Afterwards the procedure is equal to the following description for iban (see below).
- iban - IBAN of the customer. If it is a valid IBAN, the IBAN will be pinned for the current session. The customer will not be able to choose a different account, even if there are more accounts available to chose from. If the given IBAN is not in the customer list of accounts, the transaction will be aborted. In the case of an invalid IBAN XS2A will return a validation error with HTTP status code 422.
- bic - BIC of the customer. If the given BIC is valid, the step/page for entering a bank code will be skipped.
- check_amount - The account balance amount to be checked against.
- check_currency_id - The currency id of the check amount, e.g. EUR.
- metadata - An array of data which will be passed back to your application. With this field you can
for example pass information about your customer ids, order ids and the like back to your application.
Please beware of some restrictions for the
metadata
field: maximum of 3 values, maximum of a key length of 20 characters, maximum length of values is 128 characters. For privacy protection reason it is not allowed to use this field for transferring personal data (e.g. names or addresses). - merchant_id - You can fill this field with the internal ID of your merchant, if any.
Please also note the following restrictions:
- If you include a
bank_code
parameter, you must also include thecountry_id
parameter. - If you include the field
account_number
, you must also include the parameterbank_code
. - If both
iban
andaccount_number
are given,iban
will be preferred. - If you include a
check_amount
parameter, you must also includecheck_currency_id
.
Using the wizard_session_key
you can now initialize our Wizard which is running on your website.
We suggest that you store the internally used XS2A transaction id transaction
with your transaction data,
because if you later have questions about a transaction, we need this number to be able to quickly assist you.
XS2A.verify response object
{
"id": "xv_hd84kg9zns53lvh1",
"transaction": "10001-xv-abcd-abcd",
"object": "xs2a_verification",
"account_holder": "Account Holder",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"check_requested": true,
"check_amount": "100.0",
"check_currency_id": "EUR",
"check_passed": true,
"testmode": true,
"metadata": {
"custid": 4711,
"orderid": 12345
},
"merchant_id": "",
"created_at": "2014-03-23 15:55:54"
}
Explanation of XS2A.verify response fields:
Key | Type(length) | Description |
---|---|---|
id | string(20) | Transaction id |
transaction | string(19) | Internal XS2A transaction id. This id will be the same for the whole transaction |
object | string(17) | Object type, in this case a xs2a_verification |
account_holder | string(255) | Account holder name |
iban | string(40) | IBAN |
bic | string(11) | BIC |
bank_name | string(255) | Bank name |
country_id | string(3) | Two letter country code id, e.g. AT, CH, DE |
check_requested | boolean | Indicates whether or not an additional check was requested |
check_amount | number | The amount the account balance will be checked against |
check_currency_id | string(3) | Currency id of check_amount, e.g. EUR |
check_passed | boolean | Indicates whether or not the check was successful |
testmode | boolean | Indicates whether or not it is a test transaction |
metadata | array | Custom data will be returned unchanged. If no data was submitted, this field will be null |
merchant_id | string(255) | Data will be returned unchanged. |
Retrieve a list of all the XS2A.verify transactions
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications
GET /v1/verifications HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"total": 26,
"per_page": 15,
"current_page": 1,
"last_page": 2,
"from": 1,
"to": 15,
"data": [
{
"id": "xv_eR08AnBz7CeBKnzp",
"account_holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"check_requested": "0",
"check_amount": "0.0",
"check_currency_id": "EUR",
"check_passed": "0",
"testmode": "1",
"created_at": "2015-05-05 11:47:45",
"transaction": "10001-xv-zCTO-xpIT",
"metadata": null,
"merchant_id": "",
"object": "xs2a_verification"
},
]
}
To retrieve a list of all the XS2A.verify transactions, you can send a GET
request to the API endpoint
v1/verifications
. Please note that to comply with our privacy policy we only keep transaction data for
30 days. The transaction data will not be available after this period.
This will return a JSON array consisting of XS2A.verify transactions. You can use it to process this data within your application. The array will be wrapped in a pagination element.
You can also use the following GET parameters to filter the results:
Parameter | Type | Required | Description |
---|---|---|---|
account_holder | string | Optional | Filter using account holder of the account |
iban | string | Optional | Filter using iban |
bic | string | Optional | Filter using bic |
country_id | string | Optional | Filter using two letter country id |
check_requested | boolean | Optional | Filter by check_requested |
check_passed | boolean | Optional | Filter by check_passed |
merchant_id | string | Optional | Filter by merchant_id |
from,to | string | Optional | Filter by date. Pass ISO8861 conform dates (yyyy-mm-ddThh:mm:ss-zzzz). The time and timezone portions are optional and may be omitted (e.g yyyy-mm-dd or yyyy-mm-ddThh:mm:ss).. |
since | string | Optional | Filter by date (format yyyy-mm-dd or yyyy-mm-ddThh:mm:ssZ or an ISO8601 conform date. You can also supply date expressions like “-2 weeks” oder “-4 month”). This parameter has been deprectated in favor of from and to . |
Retrieve a list of XS2A.verify transactions which included an account balance check, but were not successful
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications?check_requested=true&check_passed=false
GET /v1/verifications?check_requested=true&check_passed=false HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Retrieve all transactions where a check was requested between 23.03.2014 and 25.04.2014:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications?check_requested=true&from=2014-03-23T00:00:00&to=2014-04-25T00:00:00
GET /v1/verifications?check_requested=true&from=2014-03-23T00:00:00&to=2014-04-25T00:00:00 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Example request to retrieve a single transaction as a JSON object, use the transaction id as a parameter like this:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications/xv_hd84kg9zns53lvh1
GET /v1/verifications/xv_hd84kg9zns53lvh1 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
As an alternative to the
id
you can use the internal XS2A transaction idtransaction
as parameter:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications/10001-xv-abcd-abcd
GET /v1/verifications/10001-xv-abcd-abcd HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Retrieve all events for a transactions:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications/xv_hd84kg9zns53lvh1/events
GET /v1/verifications/xv_hd84kg9zns53lvh1/events HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
XS2A.risk
curl -X POST -u api:<your-api-key> https://api.xs2a.com/v1/risks
POST /v1/risks HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 0
Session with preselected bank.
curl -X POST -u api:<your-api-key> \
-d bank_code=88888888 \
-d country_id=DE \
https://api.xs2a.com/v1/risks
POST /v1/risks HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 56
{
"bank_code": "88888888",
"country_id": "DE"
}
Session with XS2A.balance_check
curl -X POST -u api:<your-api-key> \
-d bank_code=88888888 \
-d country_id=DE \
-d xs2a_balance_check[check_amount]=100 \
-d xs2a_balance_check[check_currency_id]=EUR \
https://api.xs2a.com/v1/risks
POST /v1/risks HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 156
{
"bank_code": "88888888",
"country_id": "DE",
"xs2a_balance_check": {
"check_amount": "100",
"check_currency_id": "EUR"
}
}
Request with metadata
curl -X POST -u api:<your-api-key> \
-d bank_code=88888888 \
-d country_id=DE \
-d xs2a_balance_check[check_amount]=100 \
-d xs2a_balance_check[check_currency_id]=EUR \
-d metadata[customer_id]=4711 \
-d metadata[order_id]=abcdefg \
https://api.xs2a.com/v1/risks
POST /v1/risks HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 241
{
"bank_code": "88888888",
"country_id": "DE",
"xs2a_balance_check": {
"check_amount": "100",
"check_currency_id": "EUR"
},
"metadata": {
"customer_id": "4711",
"order_id": "abcdefg"
}
}
Response
{
"wizard_session_key": "<random-key>",
"transaction": "<internal-XS2A-ID>"
}
XS2A.risk is similar to XS2A.verify. It allows you to collect and validate a bank connection. Additionally a range of predefined checks can be applied using the retrieved account information. For more information about the predefined checks see XS2A.risk.
To create an XS2A.risk object and receive a Wizard session key use the endpoint
POST https://api.xs2a.com/v1/risks
Please make sure to include the HTTP header Content-Type: application/json
with your JSON body, if you decide to use
JSON for your POST data instead of URL encoded data.
The POST request may include the following parameters:
Parameter | Type | Required | Description |
---|---|---|---|
bank_code | number | Optional | bank code of the customers bank, requires also parameter country_id. If supplied the step/page for entering a bank code will be skipped. |
country_id | string | Optional | Two letter country code id, e.g. AT, CH, DE |
account_number | string | Optional | (national) account number of the customer |
iban | string | Optional | IBAN of the customers account |
bic | string | Optional | BIC of the customers account |
check_amount | number | Optional | Account balance amount to be checked against |
check_currency_id | string | Optional | Currency id of check_amount, e.g. EUR |
metadata | array | Optional | An array of data which will be passed back to your application |
merchant_id | string | Optional | The internal ID of your merchant, if any. |
language | string | Optional | The initial language. May be en or de . |
- account_number - The (national) account number of the customer. Is the account number valid, an IBAN will be calculated using the bank code and the account number. Afterwards the procedure is equal to the following description for iban (see below).
- iban - IBAN of the customer. If it is a valid IBAN, the IBAN will be pinned for the current session. The customer will not be able to choose a different account, even if there are more accounts available to chose from. If the given IBAN is not in the customer list of accounts, the transaction will be aborted. In the case of an invalid IBAN XS2A will return a validation error with HTTP status code 422.
- bic - BIC of the customer. If the given BIC is valid, the step/page for entering a bank code will be skipped.
- check_amount - The account balance amount to be checked against.
- check_currency_id - The currency id of the check amount, e.g. EUR.
- metadata - An array of data which will be passed back to your application. With this field you can
for example pass information about your customer ids, order ids and the like back to your application.
Please beware of some restrictions for the
metadata
field: maximum of 3 values, maximum of a key length of 20 characters, maximum length of values is 128 characters. For privacy protection reason it is not allowed to use this field for transferring personal data (e.g. names or addresses). - merchant_id - You can pass the internal ID of your merchant, if any.
Please also note the following restrictions:
- If you include a
bank_code
parameter, you must also include thecountry_id
parameter. - If you include the field
account_number
, you must also include the parameterbank_code
. - If both
iban
andaccount_number
are given,iban
will be preferred. - If you include a
check_amount
parameter, you must also includecheck_currency_id
.
Additionally, for the XS2A.risk product one or more additional checks can be requested.
You can find more information about the available checks in xs2a-risk-checks.
Each check has its own type of parameters. However they are all composed like
check_name[parameter_name]
.
Using the wizard_session_key
you can now initialize our Wizard which is running on your website.
We suggest that you store the internal used XS2A transaction id transaction
with you transaction data,
because if you later have questions about a transaction, we need this number to be able to quickly assist you.
XS2A.risk object
{
"id": "xr_hd84kg9zns53lvh1",
"transaction": "10001-xr-abcd-abcd",
"object": "xs2a_risk",
"account_holder": "Account Holder",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"testmode": true,
"metadata": null,
"merchant_id": "",
"created_at": "2014-03-23 15:55:54"
}
Explanation of XS2A.risk response fields:
Key | Type(length) | Description |
---|---|---|
id | string(20) | Transaction id |
transaction | string(19) | Internal XS2A transaction id. This id will be the same for the whole transaction |
object | string(9) | Object type, in this case a xs2a_risk |
account_holder | string(255) | Account holder name |
iban | string(40) | IBAN |
bic | string(11) | BIC |
bank_name | string(255) | Bank name |
country_id | string(2) | Two letter country code id, e.g. AT, CH, DE |
testmode | boolean | Indicates whether or not it is a test transaction |
metadata | array | Custom data will be returned unchanged. If no data was submitted, this field will be null |
merchant_id | string(255) | Data will be returned unchanged. |
Response with one or more additional checks will add be added to the XS2A.risk object as nested element
{
"id": "xr_hd84kg9zns53lvh1",
"transaction": "10001-xr-abcd-abcd",
"object": "xs2a_risk",
"account_holder": "Account Holder",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"testmode": true,
"metadata": null,
"merchant_id": "",
"created_at": "2014-03-23 15:55:54",
"xs2a_balance_check": {
"check_amount": 100,
"check_currency_id": "EUR",
"check_passed": true,
"object": "xs2a_balance_check",
"created_at": "2014-03-23 15:55:54"
}
}
A XS2A.risk might have any number of additional checks. Which one will be included, depends on the of checks that have been request during the initialization of the session.
Retrieve a list of all the XS2A.risk transactions
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/risks
GET /v1/risks HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Response
{
"total": 10,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 10,
"data": [
{
"id": "xr_6NEm0jRpXYhPP5AO",
"transaction": "10001-xr-UCnK-0K3Q",
"account_holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"testmode": "1",
"created_at": "2015-04-24 14:02:21",
"metadata": null,
"merchant_id": "",
"object": "xs2a_risk",
"xs2a_account_snapshot": {
"days": "10",
"from": "0000-00-00",
"to": "0000-00-00",
"filters": [
],
"all_tags": false,
"object": "xs2a_account_snapshot"
}
},
]
}
To retrieve a list of all the XS2A.risk transactions, you can send a GET
request to the API endpoint
v1/risks
. Please note that to comply with our privacy policy we only keep transaction data for
30 days. The transaction data will not be available after this period.
This will return a JSON array consisting of XS2A.risk transactions. You can use it to process this data within your application. The array will be wrapped in a pagination element.
You can also use the following GET
parameters to filter the results:
Parameter | Type | Required | Description |
---|---|---|---|
account_holder | string | Optional | Filter using account holder of the account |
iban | string | Optional | Filter using iban |
bic | string | Optional | Filter using bic |
country_id | string | Optional | Filter using two letter country id |
merchant_id | string | Optional | Filter by merchant_id |
from,to | string | Optional | Filter by date. Pass ISO8861 conform dates (yyyy-mm-ddThh:mm:ss-zzzz). The time and timezone portions are optional and may be omitted (e.g yyyy-mm-dd or yyyy-mm-ddThh:mm:ss).. |
since | string | Optional | Filter by date (format yyyy-mm-dd or yyyy-mm-ddThh:mm:ssZ or an ISO8601 conform date. You can also supply date expressions like “-2 weeks” oder “-4 month”). This parameter has been deprectated in favor of from and to . |
Example request to retrieve all transactions where a check was requested between 23.03.2014 and 25.04.2014 (time and timezone omitted):
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/risks?from=2014-03-23&to=2014-04-25
GET /v1/risks?from=2014-03-23&to=2014-04-25 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Example request to retrieve a single transaction as a JSON object, use the transaction id as a parameter like this:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/risks/xr_hd84kg9zns53lvh1
GET /v1/risks/xr_hd84kg9zns53lvh1 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
As an alternative to the
id
you can use the internal XS2A transaction idtransaction
as parameter:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/risks/10001-xr-abcd-abcd
GET /v1/risks/10001-xr-abcd-abcd HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Retrieve all events for a transaction:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/risks/xr_hd84kg9zns53lvh1/events
GET /v1/risks/xr_hd84kg9zns53lvh1/events HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
XS2A.risk-checks
Currently the following risk checks are available
- XS2A.account_snapshot
- XS2A.balance_check
- XS2A.balance_overview
- XS2A.cashflow_overview
- XS2A.chargeback_check
- XS2A.children_check
- XS2A.credit_check
- XS2A.direct_debit_check
- XS2A.fact_sheet
- XS2A.name_check
- XS2A.overdraft_limit_check
- XS2A.seizure_check
- XS2A.standing_orders_check
More checks will be added in the future.
XS2A.account_snapshot
A XS2A.account_snapshot is more an additional option than a whole check. A XS2A.account_snapshot offers direct access to the raw account data. The account data reflects the information at the time of the transaction.
If you use XS2A.risk for example for a loan application process, you can use the account snapshot to complete your files of the customer.
A typical workflow for a XS2A.risk check with a XS2A.account_snapshot option enabled works like this:
- Create a XS2A.risk session with enabled XS2A.account_snapshot
- Initialize and the Wizard, customer completes the login with the bank
- The XS2A application prepares the account statement (snapshot).
- Using an API call you can retrieve/download the created account statement.
Example XS2A.account_snapshot
{
// embedded in a XS2A.risk object
"xs2a_account_snapshot": {
"days": 45,
"filters": []
}
}
The XS2A.account_snapshot object accepts the following parameters:
Parameter | Type | Description |
---|---|---|
days | int | Range in days which should be used (min value: 10, max value: 365) |
from | date | A date in the format yyyy-mm-dd |
to | date | A date in the format yyyy-mm-dd |
filters | array | Filter account statements, for valid options see below |
all_accounts | bool | True, if you want to receive all accounts including their turnovers |
all_tags | bool | True, if you want full categorization of the turnovers |
The range of the returned turnovers in the the account snapshot can be either
constrained by a number of days, starting from the current date or optionally by
explicitly stating a from
and to
parameter. Notice however that the complete
account snapshot will be restricted to the given date range. That also means that
the account balance will be from the last day of the given date range.
Examples for valid filters
options are
Filter | Description |
---|---|
rent | Information about rent payments |
living-cost | Information about living cost in general |
credit | Statements for running credit liabilities |
income | Income statements |
For more filters visit the test call page and select “XS2A.risk” from the product dropdown and click the checkbox at “XS2A.account_snapshot”. You will be presented with a full list of filters.
If you want all turnovers with all available filter without specifying any filters
in the first place you may supply the all_tags
parameter. Keep in mind however that
the filter rules we apply internally may change a lot. To keep your set of filters, and
therefore your API, from unexpected changes it is advisable to provide a full list of
filters when creating the session.
Example with more than one filter
{
// embedded in a XS2A.risk object
"xs2a_account_snapshot": {
"days": 45,
"filters": [
"rent",
"income"
]
}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_account_snapshot": {
"days": 45,
"from": "0000-00-00",
"to": "0000-00-00",
"filters": [],
"all_tags": false,
"object": "xs2a_account_snapshot"
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
days | int | Range in days that were used |
from | date | The start date in the format yyyy-mm-dd |
to | date | The end date in the format yyyy-mm-dd |
filters | array | Filter account statements |
all_tags | bool | True, if the turnovers were fully categorized |
The account statement can be downloaded via a GET
call to the following URL
GET https://api.xs2a.com/v1/risks/<transaction-id>/accountSnapshot?format=pdf
The format
parameter is optional. The account snapshot is available in the following
formats: pdf
, csv
, json
and json2
. This call defaults to pdf
if the format parameter
is omitted. Please note that you have to use json2
as format if the all_accounts
parameter
was set to true.
Example Formats
Format | Example |
---|---|
download | |
csv | download |
json | download |
json2 | download |
XS2A.balance_check
The XS2A.balance_check allows the check of the account coverage against a given amount.
Example XS2A.balance_check
{
// embedded in a XS2A.risk object
"xs2a_balance_check": {
"check_amount": 100,
"check_currency_id": "EUR",
"check_passed": true,
"object": "xs2a_balance_check",
"created_at": "2014-03-23 15:55:54"
}
}
Explanation of XS2A.risk balance_check response fields:
Key | Type | Description |
---|---|---|
object | string(18) | Object type, in this case a xs2a_balance_check |
check_amount | number | The amount the account balance will be checked against |
check_currency_id | string(3) | Currency id of check_amount, e.g. EUR |
check_passed | boolean | Indicates whether or not the check was successful |
created_at | string(19) | Creation date of the object |
Example XS2A.balance_check object
{
// embedded in a XS2A.risk object
"xs2a_balance_check": {
"check_amount": 100,
"check_currency_id": "EUR"
}
}
The XS2A.balance_check object accepts the following parameters:
Parameter | Type | Required | Description |
---|---|---|---|
check_amount | number | Optional | Account balance amount to be checked against |
check_currency_id | string | Optional | Currency id of check_amount, e.g. EUR |
For more information about embedding a check into an XS2A.risk object, see XS2A.risk.
XS2a.balance_overview
XS2A.balance_overview returns the current running total of the chosen account.
An XS2A.balance_overview has no additional parameters. Just append an empty object to the XS2A.risk object to indicate you would like this check to be performed.
Example XS2a.balance_overview
{
// embedded in a XS2A.risk object
"xs2a_balance_overview": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_balance_overview": {
"balance": "135.0",
"available": "1135.0",
"limit": "1000.0",
"currency_id": "EUR",
"created_at": "2016-03-17 14:07:54",
"object": "xs2a_balance_overview"
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
balance | number | Current balance |
available | number | Current available |
limit | number | Current limit (overdraft) |
currency_id | string(3) | Currency id of above values, e.g. EUR |
XS2a.cashflow_overview
XS2A.cashflow_overview provides an cashflow overview for the requested risk date range.
An XS2A.cashflow_overview has no additional parameters. Just append an empty object to the XS2A.risk object to indicate you would like this check to be performed.
Example XS2a.cashflow_overview
{
// embedded in a XS2A.risk object
"xs2a_cashflow_overview": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_cashflow_overview": {
"cashflow": [
{
"month": 0,
"incoming": 0,
"outgoing": 0,
"minimum_balance": "135.00",
"incoming_transactions": 0,
"outgoing_transactions": 0,
"currency_id": "EUR"
},
{
"month": -1,
"incoming": 3038.07,
"outgoing": -1436.86,
"minimum_balance": -1591.44,
"incoming_transactions": 3,
"outgoing_transactions": 16,
"currency_id": "EUR"
},
{
"month": -2,
"incoming": 3038.07,
"outgoing": -833.18,
"minimum_balance": -3760.13,
"incoming_transactions": 3,
"outgoing_transactions": 6,
"currency_id": "EUR"
},
{
"month": -3,
"incoming": 0,
"outgoing": 0,
"minimum_balance": -3671.1,
"incoming_transactions": 0,
"outgoing_transactions": 0,
"currency_id": "EUR"
}
],
"created_at": "2016-03-17 14:20:51",
"object": "xs2a_cashflow_overview"
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
month | number | Relative month, e.g. current is 0, previous month is -1 and so on |
incoming | number | Amount of this month incoming transactions |
outgoing | number | Amount of this month outgoing transactions |
minimum_balance | number | The minimum (lowest) balance of the account in that month |
incoming_transactions | number | A count of this month incoming transactions |
outgoing_transactions | number | A count of this month outgoing transactions |
currency_id | string(3) | Currency id of above values, e.g. EUR |
created_at | string(19) | The objects creation date. |
object | string(22) | The object name. |
XS2a.chargeback_check
XS2A.chargeback_check returns the number of detected chargeback transactions for the account.
An XS2A.chargeback_check has no additional parameters. Just append an empty object to the XS2A.risk object to indicate you would like this check to be performed.
Example XS2a.chargeback_check
{
// embedded in a XS2A.risk object
"xs2a_chargeback_check": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_chargeback_check": {
"chargebacks_count": "2",
"chargebacks_coverage": "1",
"chargebacks_revoked": "1",
"chargebacks_sum_amount": "43.20",
"currency_id": "EUR",
"created_at": "2016-03-17 14:28:54",
"object": "xs2a_chargeback_check"
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
chargebacks_count | number | Total count of detected chargeback transactions |
chargebacks_coverage | number | Count of chargebacks which was triggered due insufficient funds |
chargebacks_revoked | number | Count of chargebacks which was triggered manually |
chargebacks_sum_amount | number | Sum over the amount of all chargebacks |
currency_id | string(3) | Currency of sum amount in ISO 4217 format |
created_at | string(19) | The objects creation date. |
object | string(21) | The object name. |
XS2A.children_check
The XS2A.children_check gathers payments from govermential facilities, which indicate how many children the account has.
This risk-check has no configuration.
Example XS2A.children_check
{
// embedded in a XS2A.risk object
"xs2a_children_check": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_children_check": {
"children_at_account_holder": 0
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
children_at_account_holder | number | Count of calculated children. |
XS2A.credit_check
The XS2A.credit_check gathers various information about a customer. The check was designed for example to be used in a loan application process without the need to resort to some other medium. Currently information on all available categories are available. For further information see our category documentation
Example XS2A.credit_check
{
// embedded in a XS2A.risk object
"xs2a_credit_check": {
"checks": [
"income",
"living-cost",
"credit"
],
"check_days": 30,
"results": {
"income": {
"amount": 0.0,
"currency": "EUR"
},
"living-cost": {
"amount": 0.0,
"currency": "EUR"
},
"credit": {
"amount": 0.0,
"currency": "EUR"
}
},
"created_at": "2014-08-22 09:47:11",
"object": "xs2a_credit_check"
}
}
Explanation of XS2A.credit_check response fields:
Key | Type | Description |
---|---|---|
checks | array | Which checks were performed |
check_days | number | Range in days that were used to calculated and gather the desired information |
results | array | List of requested checks with the corresponding calculated value |
created_at | string(19) | Creation date of the object |
object | string(17) | Object type, in this case a xs2a_credit_check |
Example XS2A.credit_check
{
// embedded in a XS2A.risk object
"xs2a_credit_check": {
"checks": [
"income",
"credit"
]
}
}
For more information about embedding a check into an XS2A.risk object, see XS2A.risk.
XS2A.direct_debit_check
The XS2A.direct_debit_check uses various metrics to determine the best date to execute a direct debit to minimize the risk of a default due to a lack of account coverage.
Example XS2A.direct_debit_check
{
// embedded in a XS2A.risk object
"xs2a_direct_debit_check": {
"check_amount": 100,
"check_currency_id": "EUR",
"start_date": "2014-03-23",
"end_date": "2014-03-31",
"recommendation": "DATE",
"recommendation_date": "2014-03-25",
"created_at": "2014-03-23 15:55:54",
"object": "xs2a_direct_debit_check"
}
}
Explanation of XS2A.risk direct_debit_check response fields:
Key | Type | Description |
---|---|---|
object | string(23) | Object type, in this case a xs2a_direct_debit_check |
check_amount | number | Account balance amount to be checked against |
check_currency_id | string(3) | Currency id of check_amount, e.g. EUR |
start_date | string(10) | Date format is “YYYY-mm-dd” |
end_date | string(10) | Date format is “YYYY-mm-dd” |
recommendation | string(6) | Values will either be ANY , DATE or REJECT |
recommendation_date | string(10) | Date format is “YYYY-mm-dd” |
created_at | string(19) | Creation date of the object |
- start_date - An optional field. The date format is “YYYY-mm-dd”. If a start_date is given, the field “end_date” has to be set as well. The start date can be no earlier than the day after the transaction. In case the start date is invalid or not set, the earliest bank work day will be used.
- end_date - An optional field. The date format is “YYYY-mm-dd”. The end date has to be at lest 3 days after the start date and can be a maximum of 30 days into the future. If there is no end date given, the maximum of 30 days will be used.
- recommendation - This field represents the response from our system. The values will
either be
ANY
,DATE
orREJECT
. IfANY
is returned, it should be save to execute the direct debit at any time. IfDATE
is returned, we suggest a date for executing the direct debit in the fieldrecommendation_date
. In case of aREJECT
it is not recommended to execute a direct debit, because the amount is likely not be covered. For aREJECT
the returnedrecommendation_date
will always be “0000-00-00”. - recommendation_date - If the
recommendation
isDATE
, this will be the recommended time to execute a direct debit. In some cases, this date might be out of the start-/end-date range supplied (reasons might be holidays etc.). In case ofREJECT
this field will always be set as “0000-00-00”.
Example XS2A.direct_debit_check
{
// embedded in a XS2A.risk object
"xs2a_direct_debit_check": {
"check_amount": 100,
"check_currency_id": "EUR",
"start_date": "2014-03-23",
"end_date": "2014-03-31"
}
}
The XS2A.direct_debit_check object accepts the following parameters:
Parameter | Type | Description |
---|---|---|
check_amount | number | Account balance amount to be checked against |
check_currency_id | string | Currency id of check_amount, e.g. EUR |
start_date | string | Date format is “YYYY-mm-dd” |
end_date | string | Date format is “YYYY-mm-dd” |
- start_date - An optional field. The date format is “YYYY-mm-dd”. If a start_date is given, the field “end_date” has to be set as well. The start date can be no earlier than the day after the transaction. In case the start date is invalid or not set, the earliest bank work day will be used.
- end_date - An optional field. The date format is “YYYY-mm-dd”. The end date has to be at lest 3 days after the start date and can be a maximum of 30 days into the future. If there is no end date given, the maximum of 30 days will be used.
By using the start- and end-date option, you can specify a direct debit date range that is suitable to your liking. Our system will try to find the best day to execute a direct debit in your given date range.
For more information about embedding a check into an XS2A.risk object, see XS2A.risk.
XS2A.fact_sheet
The XS2A.fact_sheet generates a printable PDF with the most important facts about the customers account.
Parameter | Type | Description |
---|---|---|
limit_turnover_days | number | (optional) If needed limit the fetched turnovers to create a fact_sheet. Default 365. Valid Range: 10 - 365 |
Example XS2A.fact_sheet
{
// embedded in a XS2A.risk object
"xs2a_fact_sheet": {
"limit_turnover_days": 365
}
}
You are able to Download a generated PDF file.
Download Fact Sheet PDF
GET v1/risks/<risk_id>/factSheet?format=pdf HTTP/1.1
Host: api.xs2a.com
Reponse: 200 OK
PDF-Binary
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/risks/<risk_id>/factSheet?format=pdf
Also it is possible to get the calculated data, which is used to generate the factsheet as JSON.
Download Fact Sheet JSON
GET v1/risks/<risk_id>/factSheet?format=json HTTP/1.1
Host: api.xs2a.com
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/risks/<risk_id>/factSheet?format=json
Field | Content |
---|---|
monthlySums | Contains sums of all turnovers within a month |
monthlyAverages | average balance in last 3, 6 and 12 months |
facts | A list of facts we gathered from the account |
income | a list of income and their averages |
incomeAverages | Average income in last 3, 6 and 12 months |
spendings | A list of spendings and their averages |
spendingAverages | Average spendings in last 3, 6 and 12 months |
reoccurringTurnovers | A list of categories and reoccurring turnovers of the last 6 month |
cashFlow | A list of daily balances |
overdraftLimit | Overdraft limit data. See here |
standingOrders | A list of standing orders |
chargebacks | A list of all chargebacks on this account |
XS2A.name_check
The XS2A.name_check compares a given name and firstname with the extracted account holder.
Example XS2A.name_check
{
// embedded in a XS2A.risk object
"xs2a_name_check": {
"match": true,
"similarity": 100,
"object": "xs2a_name_check",
"created_at": "2015-11-11 15:55:54"
}
}
Explanation of XS2A.risk name_check response fields:
Key | Type | Description |
---|---|---|
object | string(15) | Object type, in this case a xs2a_name_check |
match | boolean | Indicates whether on not the given name matches with the extracted bank holder |
similarity | number | A value between 0 and 100. A higher value means the values matched better |
created_at | string(19) | Creation date of the object |
Example XS2A.name_check object
{
// embedded in a XS2A.risk object
"xs2a_name_check": {
"name": "Mustermann",
"firstname": "Hartmut"
}
}
The XS2A.name_check object accepts the following parameters:
Parameter | Type | Required | Description |
---|---|---|---|
name | string | Required | Name to compare against. Usually the surname. |
firstname | string | Required | Firstname to compare against. |
For more information about embedding a check into an XS2A.risk object, see XS2A.risk.
XS2a.overdraft_limit_check
XS2A.overdraft_limit_check returns the number of booking days of the given risk range. The number of days the account used the overdraft limit, the maximum amount of overdraft used, the average and the median used overdraft.
An XS2A.overdraft_limit_check has no additional parameters. Just append an empty object to the XS2A.risk object to indicate you would like this check to be performed.
Example XS2A.overdraft_limit_check
{
// embedded in a XS2A.risk object
"XS2A.overdraft_limit_check": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_overdraft_limit_check": {
"booking_days": "23",
"overdraft_limit_days": "23",
"maximum_overdraft_used": "-3760.13",
"average_overdraft_used": "-2032.85",
"median_overdraft_used": "-1466.21",
"currency_id": "EUR",
"created_at": "2016-03-17 14:39:44",
"object": "xs2a_overdraft_limit_check"
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
booking_days | number | Count of booking days in the date range found |
overdraft_limit_days | number | Count of days the account used the overdraft limit |
maximum_overdraft_used | number | Maximum amount the overdraft was used in that date range |
average_overdraft_used | number | Average amount the overdraft was used in that date range |
median_overdraft_used | number | Median amount the overdraft was used in that date range |
currency_id | string(3) | Currency id of above values, e.g. EUR |
created_at | string(19) | The objects creation date. |
object | string(26) | The object name. |
XS2a.seizure_check
XS2a.seizure_check allows you to check for a seizire account.
Example XS2a.seizure_check
{
// embedded in a XS2A.risk object
"xs2a_seizure_check": {}
}
Response
{
"xs2a_seizure_check": {
"is_seizure": "0",
"created_at": "2017-03-30 16:14:32",
"object": "xs2a_seizure_check"
}
}
Explanation of response fields:
Parameter | Type | Description |
---|---|---|
is_seizure | number | 1 if the customers account is a seizure account |
XS2a.standing_orders_check
XS2A.standing_orders_check allows you to retrieve all standing orders from an account. An XS2A.standing_orders_check has no additional parameters. Simply append an empty object to the XS2A.risk object to indicate you would like this check to be performed.
Example XS2a.standing_orders_check
{
// embedded in a XS2A.risk object
"xs2a_standing_orders_check": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_standing_orders_check": {
"standing_orders": [
{
"sender_account": {
"holder": "Account Holder",
"description": "Account description",
"iban": "DE1234...",
"bic": "BNK123...",
"country_id": "DE"
},
"recipient_account": {
"holder": "Recipient Holder",
"description": "",
"iban": "DE4321...",
"bic": "BNK321...",
"country_id": "DE"
},
"amount": 500,
"currency": "EUR",
"purpose": "Purpose",
"frequency": "m",
"frequency_interval": 1,
"day": 31,
"start_execution": "2014-11-05",
"end_execution": null
}
],
"created_at": "2016-03-23 12:34:56",
"object": "xs2a_standing_orders_check"
}
}
The standing_orders
-property contains the list of all standing orders objects.
Explanation of response fields:
Key | Type | Description |
---|---|---|
object | string(26) | Object type, in this case a xs2a_standing_orders_check |
sender_account | object | Account object |
recipient_account | object | Account object |
amount | number | Amount to transfer |
currency | string(3) | Currency id of amount, e.g. EUR |
purpose | string(54) | Purpose of the transfer |
frequency | string(1) | Frequency of standing order, d = daily, w = weekly, m = monthly, y = yearly |
frequency_interval | integer | Frequency interval. For monthly execution frequency would be m , interval would be 1 . For a bi-weekly execution frequency would be w , interval would be 2 . 0 is used in case for a non standardized intervals (e.g. explicit month selection). |
day | integer | Day of the execution. In case of daily or weekly frequency the range is 1-7 (1 = Monday, 7 = Sunday). In case of monthly or yearly frequency it is 1-31. 31 is used if the execution is sheduled for the last day of the month. |
start_execution | string(10) | Date of the first or next execution of the standing order, format YYYY-mm-dd. |
end_execution | string(10) | Date of the last execution of the standing order, format YYYY-mm-dd. |
created_at | string(19) | Creation date of the object |
A typical example would be rent payments executed at the end of every month.
The frequency
is m
for monthly, frequency_interval
is 1
since it should be
executed every month. The key day
is 31
because this will represent either the
actual 31st of that month or the last day of the month in case the current month
does not have a 31st (Ultimo).
In rare cases frequency_interval
might be 0
. It indicates irregular intervals in a non standardized format.
XS2a.all_accounts_check
XS2A.all_accounts_check is like the XS2a.account_snapshot more of an additional option than an individual check. If this option is selected, all visible accounts are extracted and reported back.
An XS2A.all_all_accounts_check has no additional parameters. Just append an empty object to the XS2A.risk object to indicate you want this check to be performed.
Example XS2a.all_accounts_check
{
// embedded in a XS2A.risk object
"xs2a_all_accounts_check": {}
}
Response
{
// embedded in a XS2A.risk object
"xs2a_all_accounts_check": {
"accounts": [
{
"holder": "Account Holder",
"description": "Account description",
"iban": "DE1234...",
"bic": "BNK123...",
"joint_account": false
},
{
"holder": "Account Holder",
"description": "Account describes No 2",
"iban": "DE1234...",
"bic": "BNK123...",
"joint_account": false
},
{
"holder": "Account Holder",
"description": "Visa Card",
"iban": "",
"bic": "BNK123...",
"joint_account": false
}
],
"created_at": "2015-03-23 12:34:56",
"object": "xs2a_all_accounts_check"
}
}
The accounts
-property contains the list of all account objects.
Please note that the 3rd account in the list has an empty
iban
property. This is especially common for savings accounts and credit cards.
XS2A.pay
curl -X POST -u api:<your-api-key> \
-d recipient_holder=Holder \
-d recipient_iban=DE04888888880087654321 \
-d recipient_bic=TESTDE88XXX \
-d recipient_country_id=DE \
-d amount=5.00 \
-d currency_id=EUR \
-d purpose=Purpose \
https://api.xs2a.com/v1/payments
POST /v1/payments HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 229
{
"recipient_holder": "Holder",
"recipient_iban": "DE04888888880087654321",
"recipient_bic": "TESTDE88XXX",
"recipient_country_id": "DE",
"amount": "5.00",
"currency_id": "EUR",
"purpose": "Purpose"
}
Response
{
"wizard_session_key": "<random-key>",
"transaction": "<internal-XS2A-ID>"
}
XS2A.pay offers a payment solution. The customer uses his online banking credentials. Optional security checks will be executed to counter fraud and other suspicious activity. After that the transfer of a fixed amount and purpose will be sent to a predefined recipient account. The customer authorizes the transaction with a TAN after which the bank is executing the transfer.
The customer is the sender of the transfer. You as PSP/merchant are the recipient of the payment.
To create an XS2A.pay object and receive a Wizard session key use the endpoint
POST https://api.xs2a.com/v1/payments
Please make sure to include the HTTP header Content-Type: application/json
with your JSON body, if you decide to use
JSON for your POST data instead of URL encoded data.
The POST request may include the following parameters:
Parameter | Type | Required | Description |
---|---|---|---|
amount | number | Required | Amount to be transferred |
currency_id | string | Required | Currency id of the amount (currently only EUR) |
purpose | string | Required | Purpose of the transfer |
metadata | array | Optional | An array of data which will be passed back to your application |
language | string | Optional | The initial language. May be en or de . |
merchant_id | string | Optional | The internal ID of your merchant, if any. |
sender_holder | string | Optional | Holder name of sender account owner |
sender_iban | string | Optional | IBAN of the sender account |
sender_bic | string | Optional | BIC of the sender account |
sender_country_id | string | Optional | Two letter country code id of the sender account, e.g. AT, CH, DE |
recipient_holder | string | Required | Account holder of the recipient account |
recipient_iban | string | Required | IBAN of the recipient account |
recipient_bic | string | Optional | BIC of the recipient account |
recipient_street | string | Optional | Street of the recipient account |
recipient_zip | string | Optional | Zip-code of the recipient account |
recipient_city | string | Optional | City of the recipient account |
recipient_country_id | string | Optional | Two letter country code id, e.g. AT, CH, DE |
Payment-Parameters
- metadata - An array of data which will be passed back to your application. With this field you can
for example pass information about your customer ids, order ids and the like back to your application.
Please beware of some restrictions for the
metadata
field: maximum of 3 values, maximum of a key length of 20 characters, maximum length of values is 128 characters. For privacy protection reason it is not allowed to use this field for transferring personal data (e.g. names or addresses). - purpose - We suggest to keep the purpose as short as possible and to place critical information at the beginning of the purpose. The reason for this suggestion is that we might have to limit the length of your given purpose. A SEPA purpose can be up to 140 characters. However some banks only offer a reference field which is limited to 35 characters. If your purpose is longer than bank supported purpose field, we will shorten it to the maximum length supported by that bank. Not all characters are supported for the purpose field. Sender banks impose different rules for the purpose field, therefore we suggest to limit the character set to a-z, A-Z, 0-9. If you use other characters please be advised that we might have to remove or replace characters considered invalid by the sender bank. We usually will replace the invalid characters with a whitespace or normalize the characters.
- recipient_holder - Sender banks impose different rules for the recipient_holder field, we suggest to limit the character set to a-z, A-Z, 0-9. If you use other characters please be advised that we might have to remove or replace characters considered invalid by the sender bank. We usually will replace the invalid characters with a whitespace or normalize the characters.
- merchant_id - You may fill this field with the internal ID your merchant, if you are a PSP.
Sender Account (optional, will be determined by XS2A)
sender_holder - Name of the account holder. If this is set, the account holder will be pinned and validated for the current session. The customer will not be able to choose an account with a different name than provided. The name will be compared with our XS2A.name_check module. A match is not only string equals. To a certain point changes in the name will be tolerated. (i.e. a prepending academic title will not break the match)
sender_iban - IBAN of the sender account. If it is a valid IBAN, the IBAN will be pinned for the current session. The customer will not be able to choose a different account, even if there are more accounts available to chose from. If the given IBAN is not in the customer list of accounts, the transaction will be aborted. In the case of an invalid IBAN XS2A will return a validation error with HTTP status code 422.
sender_bic - BIC of the sender account. If the given BIC is valid, the step/page for entering a bank code will be skipped.
Valid test mode data for a recipient account:
- Account holder: anything
- IBAN: DE62888888880012345678
- BIC: TESTDE88XXX
- Country: DE
Please use these recipient account data in case you don’t have any other recipient at hand. Also please keep in mind that the recipient information is only valid in combination with a TEST-API-key.
Using the wizard_session_key
you can now initialize our Wizard which is running on your website.
We suggest that you store the internal used XS2A transaction id transaction
with you transaction data,
because if you later have questions about a transaction, we need this number to be able to quickly assist you.
XS2A.pay response object
{
"id": "xp_fSdkfjS2R2S5x1pu",
"transaction": "10001-xp-abcd-abcd",
"object": "xs2a_payment",
"sender_holder": "Holder Customer",
"sender_iban": "DE62888888880012345678",
"sender_bic": "TESTDE88XXX",
"sender_bank_name": "Testbank",
"sender_country_id": "DE",
"recipient_holder": "Holder",
"recipient_iban": "DE04888888880087654321",
"recipient_bic": "TESTDE88XXX",
"recipient_bank_name": "Testbank",
"recipient_country_id": "DE",
"purpose": "Purpose",
"amount": 5,
"currency_id": "EUR",
"testmode": true,
"payment_status": "RECEIVED",
"metadata": {
"name": "value"
},
"merchant_id": ""
}
Explanation of XS2A.pay response fields:
Key | Type | Description |
---|---|---|
id | string(20) | Transaction id |
transaction | string(19) | Internal XS2A transaction id. This id will be the same for the whole transaction |
sender_holder | string(255) | Account holder of the sender account |
sender_iban | string(40) | IBAN of the sender account |
sender_bic | string(11) | BIC of the sender account |
sender_bank_name | string(255) | Name of the sender bank |
sender_country_id | string(2) | Two letter country code id of the sender account, e.g. AT, CH, DE |
recipient_holder | string(255) | Account holder of the recipient account |
recipient_iban | string(40) | IBAN of the recipient account |
recipient_bic | string(11) | BIC of the recipient account |
recipient_bank_name | string(255) | Name of the recipient bank |
recipient_country_id | string(2) | Two letter country code id of the recipient account, e.g. AT, CH, DE |
purpose | string(54) | Purpose of transfer |
amount | number | Amount to transfer |
currency_id | string(3) | Currency id of amount, e.g. EUR |
testmode | boolean | Indicates whether or not it is a test transaction |
payment_status | string(9) | Payment status of the transaction, values NONE, RECEIVED, LOSS |
metadata | array | Custom data will be returned unchanged. If no data was submitted, this field will be null |
merchant_id | string(255) | Data will be returned unchanged. |
object | string(12) | Object type, in this case a xs2a_payment |
- payment_status - Payment status of the transaction. Three values are possible NONE = unknown, RECEIVED = payment received, LOSS = payment not received.
The payment_status field is intended to be used to notify us that the payment has been received or has been lost.
Example use case:
- Merchant uses XS2A as integrated payment solution
- Customer uses XS2A in checkout process
- The involved banks take for example two days to process the transfer
- The merchant after the two days matches the transaction in the bank account statements
- Merchant can now call /payments/<transaction>/received
- In case the money was not received, the merchant would call /payments/<transaction>/loss
This mechanism helps us to determine reasons why a payment might not did go through even though the bank reported a successful transfer. It really helps us to improve our service and combating fraud.
Retrieve a list of all the XS2A.pay transactions
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/payments
GET /v1/payments HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Response
{
"total": 35,
"per_page": 15,
"current_page": 1,
"last_page": 3,
"from": 1,
"to": 15,
"data": [
{
"id": "xp_irCumJEUY550DLe2",
"transaction": "10001-xp-ERB6-4cEm",
"sender_holder": "MUSTERMANN, HARTMUT",
"sender_iban": "DE62888888880012345678",
"sender_bic": "TESTDE88XXX",
"sender_bank_name": "Testbank",
"sender_country_id": "DE",
"recipient_holder": "Holger Baumhaus",
"recipient_iban": "DE08500105175412638463",
"recipient_bic": "TESTDE88",
"recipient_bank_name": "Testbank",
"recipient_country_id": "DE",
"purpose": "234234",
"amount": "1.1",
"currency_id": "EUR",
"payment_status": "NONE",
"testmode": "1",
"metadata": null,
"merchant_id": "",
"created_at": "2015-04-24 14:03:00",
"object": "xs2a_payment"
}
]
}
To retrieve a list of all the XS2A.pay transactions, you can send a GET
request to the API endpoint
v1/payments
. Please note that to comply with our privacy policy we only keep transaction data for
30 days. The transaction data will not be available after this period.
This will return a JSON array consisting of XS2A.verify transactions. You can use it to process this data within your application. The array will be wrapped in a pagination element.
You can also use the following GET parameters to filter the results:
Parameter | Type | Required | Description |
---|---|---|---|
sender_holder | string | Optional | Holder of the sender account |
sender_iban | string | Optional | IBAN of the sender account |
sender_bic | string | Optional | BIC of the sender account |
sender_account_number | string | Optional | Account number of the sender account |
sender_bank_code | string | Optional | National bank code of the sender account |
sender_country_id | string | Optional | Two letter country code id of the sender account, e.g. AT, CH, DE |
recipient_holder | string | Optional | Holder of the recipient account |
recipient_iban | string | Optional | IBAN of the recipient account |
recipient_bic | string | Optional | BIC of the recipient account |
recipient_country_id | string | Optional | Two letter country code id of the recipient account, e.g. AT, CH, DE |
amount | number | Optional | Amount to transfer |
purpose | string | Optional | Purpose of transfer |
from,to | string | Optional | Filter by date. Pass ISO8861 conform dates (yyyy-mm-ddThh:mm:ss-zzzz). The time and timezone portions are optional and may be omitted (e.g yyyy-mm-dd or yyyy-mm-ddThh:mm:ss).. |
since | string | Optional | Filter by date (format yyyy-mm-dd or yyyy-mm-ddThh:mm:ssZ or an ISO8601 conform date. You can also supply date expressions like “-2 weeks” oder “-4 month”). This parameter has been deprectated in favor of from and to . |
Example request to retrieve all transactions where a check was requested between 23.03.2014 and 25.04.2014:
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/payments?from=2014-03-23T00:00:00&to=2014-04-25T00:00:00
GET /v1/payments?from=2014-03-23T00:00:00&to=2014-04-25T00:00:00 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Example request to retrieve a single transaction as a JSON object, use the transaction id as a parameter like this:
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/payments/xp_hd84kg9zns53lvh1
GET /v1/payments/xp_hd84kg9zns53lvh1 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
As an alternative to the
id
you can use the internal XS2A transaction idtransaction
as parameter:
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/payments/10001-xp-abcd-abcd
GET /v1/payments/10001-xp-abcd-abcd HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Retrieve all events for a transaction:
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/payments/xp_hd84kg9zns53lvh1/events
GET /v1/payments/xp_hd84kg9zns53lvh1/events HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
To change the payment status of a transaction use the following API calls:
POST v1/payments/<transaction-id>/received
POST v1/payments/<transaction-id>/loss
These api calls allow you to mark a transaction as received or loss. If you
perform a payment matching in your application, you can use these endpoints to change
the payment status on our XS2A platform. A POST
call to the endpoint
v1/payments/<transaction-id>/received
marks the transaction as received. A call
to v1/payments/<transaction-id>/loss
will mark the transaction as a loss. Both calls
will include the full xs2a_payment
object in the response.
Marking the payment status of a transaction will also fire an Event with the
type transaction.updated
. You can use this event to get a notification via a
webhook. More information is available in events and webhooks.
Sessions
GET /v1/sessions/{transaction-id}
This will return a wizard_session object, with the following fields:
field | type | description |
---|---|---|
id | string | Internal identifier. Format: ws_xxxxxxxxxxxxxxxx |
transaction | string | Public transaction identifier. Format: 00000-xx-xxxx-xxxx |
wizard_session_key | string | Key to start the wizard |
product | string | xs2a_risk , xs2a_pay or xs2a_verify |
parameters | object | An array which contains the current wizard configuration. |
last_error | string | The last occurred error. This is overwritten, if another error occurs. |
testmode | boolean | true if this session runs in testmode. false otherwise. |
finished | boolean | true if this session was finished successfully. false if not or still running. |
current_step | string | The current wizard step of this session. |
created_at | string | Time of creation |
object | string | String with content wizard_session |
To query this, you can use the transaction-id, which is returned, after the session is created.
XS2A.api
The XS2A.api is a set of APIs that make it possible to manage a users bank accounts in an asyncronous way. This makes the suitable for use in for example PFM tools. The API authentication is slightly different from the rest of the APIs, which makes it possible to deploy the API client including the API keys directly to mobile devices.
Structure
The entities that can be managed using the XS2A.api are as follows:
- bank_user - A person with one or more bank logins.
- bank_user_access_token - Access tokens that belong to a specific user, to access the rest of the API on behalf of that user.
- bank_connection - A login to a specific bank. The bank login consists of a bank code and a bank name and a syncronisation method.
- bank_account, bank_account_balance and bank_account_turnovers - The bank accounts and the bank account contents of the user.
Basic Flow and Authentication
The authentication to the API is divided into two parts. The first part or the API is accessed via the standard authentication as described in the authentication chapter. This part of the API can be used to create bank users and manage access tokens. These access tokens enable to access the rest of the API of behalf of a user.
So the basic flow of this API is as follows:
- Create a bank user using the global API key.
- Create an access token for that bank user, to be able to access the API on behalf of the user. Use the new access token from here on instead of the global API key.
- Create a bank connection for the user.
- Display a wizard for that bank connection for the user.
- The user completes the wizard, by entering her bank login credentials.
- Retrieve the account contents like balance and transactions.
Bank Users
Creating a user
curl -X PUT -u api:<your-api-key> \
-d email=user@example.com \
-d name=Username \
https://api.xs2a.com/v1/users
PUT /v1/verifications HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 71
email=user@example.com&name=Username
{
"id": "bus_Ck7nGg05TK68jd9O",
"name": "Username",
"email": "user@example.com",
"testmode": true,
"created_at": "2017-11-24T16:07:52Z",
"object": "bank_user"
}
Retrieve a paginated list of all the users
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/users
GET /v1/api/users HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"total": 1,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 15,
"data": [
{
"id": "bus_Ck7nGg05TK68jd9O",
"name": "Username",
"email": "user@example.com",
"testmode": true,
"created_at": "2017-11-24T16:07:52Z",
"object": "bank_user"
}
]
}
Retrieve a single user
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/users/bus_Ck7nGg05TK68jd9O
GET /v1/api/users/bus_Ck7nGg05TK68jd9O HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "bus_Ck7nGg05TK68jd9O",
"name": "Username",
"email": "user@example.com",
"testmode": true,
"created_at": "2017-11-24T16:07:52Z",
"object": "bank_user"
}
The endpoint
https://api.xs2a.com/v1/api/users
allows to create and delete bank users. A bank user is basically a person that has one or more logins to an online banking portal, a bank connection. In XS2A.api a bank user is mainly an entity which is used to aggregate bank account information on, therefore it does not have many attributes.
A user has has the following attributes:
Attribute | Type | Description |
---|---|---|
id | string | The ID of the bank user. |
name | string | The name of the user. |
string | An email adress (optional). | |
testmode | boolean | True, if this user has been created with a testing API key, false otherwise. |
created_at | string | The creation time of the user. |
object | string | The value bank_user . |
Creating a user
To create a bank user, issue a PUT
request to the URL. The PUT
request can have these parameters:
Parameter | Type | Required | Description |
---|---|---|---|
name | string | Required | The name of the user. |
string | Optional | The email of the user. |
The response will contain the newly created bank user.
Retrieve a list of users
To retrieve a list of all bank users, issue a GET
request on this API endpoint. The list is a standard pagination repsonse as described here.
Get a single user
To get a single user issue a GET
request on the resource URL, which is constructed as follows:
https://api.xs2a.com/v1/api/users/{$user-id}
Delete a user
To delete a user, issue a DELETE
request on the resource URL.
Access Tokens
Creating an access token
curl --user api:<your-api-key> \
-X PUT \
-d valid_until='2018-12-01 10:00:00' \
http://localhost:8000/v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens
PUT /v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 0
valid_until=2018-12-01 10:00:00
{
"id": "uat_ELdQ3VHoO0C3IPc3",
"token": "5Q1JCKqf1ONDw6SHZT4DECyrn28xm1ct",
"valid_until": "2017-12-18T12:13:27Z",
"created_at": "2017-12-18T11:13:27Z",
"object": "bank_user_access_token"
}
Retrieve a paginated list of access tokens
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens
GET /v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"total": 1,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 15,
"data": [
{
"id": "uat_ELdQ3VHoO0C3IPc3",
"token": "5Q1JCKqf1ONDw6SHZT4DECyrn28xm1ct",
"valid_until": "2017-12-18T12:13:27Z",
"created_at": "2017-12-18T11:13:27Z",
"object": "bank_user_access_token"
}
]
}
Retrieve a single token
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens/uat_ELdQ3VHoO0C3IPc3
GET /v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens/uat_ELdQ3VHoO0C3IPc3 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "uat_ELdQ3VHoO0C3IPc3",
"token": "5Q1JCKqf1ONDw6SHZT4DECyrn28xm1ct",
"valid_until": "2017-12-18T12:13:27Z",
"created_at": "2017-12-18T11:13:27Z",
"object": "bank_user_access_token"
}
Refreshing an access token
curl -X PATCH -u api:<your-api-key> \
https://api.xs2a.com/v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens/uat_ELdQ3VHoO0C3IPc3
PATCH /v1/api/users/bus_Ck7nGg05TK68jd9O/accesstokens/uat_ELdQ3VHoO0C3IPc3 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "uat_ELdQ3VHoO0C3IPc3",
"token": "5Q1JCKqf1ONDw6SHZT4DECyrn28xm1ct",
"valid_until": "2017-12-19T18:13:27Z",
"created_at": "2017-12-18T11:13:27Z",
"object": "bank_user_access_token"
}
To be able to access the rest of the API on behalf of the user you just created, you have to create API access tokens. The API endpoint to manage access tokens is:
https://api.xs2a.com/v1/users/{$user-id}/accesstokens
Where {$user-id}
must be an ID of a bank user.
An access token has has the following attributes:
Attribute | Type | Description |
---|---|---|
id | string | The ID of the token. |
token | string | The actual access token. |
valid_until | string | The date-time this token expires. |
created_at | string | The creation time. |
object | string | The value bank_user_access_token . |
Creating an access token
To create an access token, issue a PUT
request to the API endpoint. The generated access token is valid for one hour before it expires by default. It is possible to set a specific expiration-date by the following parameter:
Parameter | Type | Required | Description |
---|---|---|---|
valid_until | string | Optional | Expiration-date of access token in date-time string (Format: YYYY-MM-DD hh:mm:ss). |
The response will contain the newly created access token.
Retrieving a list of tokens
To retrieve a list of access tokens issue a GET
request on the API endpoint. The list is a standard pagination repsonse as described here.
Get a single token
To get a single token issue a GET
request on the resource URL, which is constructed as follows:
https://api.xs2a.com/v1/api/users/{$user-id}/accesstokens/{$token-id}
Delete a token
To delete a user, issue a DELETE
request on the resource URL.
Refresh a token
To refresh an access token and set a new expiration date for it, issue a PATCH
request to the URL https://api.xs2a.com/v1/api/users/{$user-id}/accesstokens/{$token-id}
.
Parameter | Type | Required | Description |
---|---|---|---|
valid_until | string | Optional | Expiration-date of access token in date-time string (Format: YYYY-MM-DD hh:mm:ss). |
The response will contain the refreshed access token.
Using an access token
To use the access token and access the rest of the API on behalf of the user, simply replace the global API key with the generated access token. That means, still use Basic-Authentication with api
as the username and the newly generated access token as the password.
Subsequent API calls with then be done on behalf of the user, that owns the access token.
Bank Connections
Bank connection represents a login to a specific bank. The creation of a bank connection always requires user interaction. The user has to select the bank she wants to connect and provide her login credentials to that bank. This process in done in our wizard, that guides the end user through the process.
The wizard itself comes in two flavors, the first on is a complete Javascript implementaion of the wizard. The Javascript implementation is by far the easiest to use, with the use of CSS it’s 100% compatible with most layouts and can be strongly customized. See the chapter on client integration for details on how to embedd the Javascript wizard.
The second option is the Wizard-API, which provides and API that is queried to guide the user throught the bank login process. Whenever embedding the Javascript wizard on a page or an app is not option, the use of the Wizard-API should be considered. For morre information on how to integrate this API see the chapter Wizard-API.
Bank connection can be synced. Syncing a bank connection means that the login to the bank is repeated, the new balance and the new list of turnovers is fetched and the list of accounts associated to the bank user is updated accordingly. Syncing a bank connection can be done in three different modes:
- full - If a bank connections
sync_mode
is set tofull
, the bank credentials are stored in XS2A and the connection will be synced automatically one a day. - shared - If
sync_mode
is set to shared, XS2A will collect the credentials, encrypt them, cut the cipher in half and make one half of the credentials available at the end of the session. This way neither XS2A, nor the client has access to the full set of credentials. The sync of a bank connection has then to be done via API, providing the other half of the credential cipher as an argument to the sync call. - none - The connection will not be synced automatically. Everytime a sync is initiated via the API, the user has to provide her bank credentials via the wizard.
A bank connection object consists of these attributes:
Attribute | Type | Description |
---|---|---|
id | string | The ID of the bank connection. |
bic | string | The banks BIC. |
bank_name | string | The banks name. |
country_id | string | The banks country. |
sync_mode | string | The mode in which this bank connection syncs itself. |
sync_active | boolean | If the bank connection is still automatically syncing. |
sync_message | string | The last error message, if a sync failed. |
sync_fail_counter | integer | The sync fail counter. After 3 failed attempts a bank connection is permanently disabled and has to be deleted and recreated. |
last_synced | string | The date of the last sync run. |
testmode | boolean | True, if this is a test connection. |
created_at | string | The creation time. |
object | string | The value bank_connection . |
The API endpoint for managing bank connections is
https://api.xs2a.com/v1/connections
This API endpoint is accessed in the user scope. This means that instead of the API key a user specific access token must be used.
Creating a bank connection
Creating a bank connection
curl --user api:{$the-bank-users-access-token} \
-X PUT \
-d sync_mode=full \
-d country_id=DE \
https://api.xs2a.com/v1/connections
PUT /v1/connections HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 28
sync_mode=full&country_id=DE
{
"wizard_session_key": "2JB4yVDFzK6UV7vlkTRVgEzYigjTDWnefDs4cKUb",
"transaction": "10001-bcs-GseB-mcBJ"
}
Retrieving a bank connection
curl --user api:{$the-bank-users-access-token} \
https://api.xs2a.com/v1/connections/bcn_BnB6mQLsHKZacYvC
PUT v1/connections/bcn_BnB6mQLsHKZacYvC HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "bcn_BnB6mQLsHKZacYvC",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"sync_mode": "full",
"sync_active": true,
"sync_message": "",
"sync_fail_counter": 0,
"last_synced": "2017-12-06T13:07:25Z",
"testmode": true,
"created_at": "2017-12-06T13:01:01Z",
"object": "bank_connection"
}
To create a bank connection you issue a PUT
request on the API endpoint. The parameters for the creation of a bank connection are
Parameter | Type | Description |
---|---|---|
sync_mode | string | The mode, how to sync the bank connection. full, shared or none. |
bic | string | The BIC of the bank, if known already. |
country_id | string | The country ID of the bank, if known already. |
The creation of a bank connection always requires user interaction. Therefore the bank connection can not be created imediately. Instead this call will return a wizard_session_key
that must be used to start a wizard.
A wizard is used to guide the user through the login process to her bank. The login proocess is modeled as close to the real bank as possible. A wizard is therefore basically a set of forms that has to be displayed to the user.
The wizard can either be a Javascript widget, that can be embedded on the website or the mobile app or a pure API solution, that does not require Javascript, but is a little harder to implement.
For the Javascript wizard integration, please refer to the chapter on client integration. For the pure API solution, please refer to the chapter on the Wizard-API.
Retrieving the list of bank connections
To retrieve a paginated list of all bank connections for a user issue a GET
request on the bank connection endpoint https://api.xs2a.com/v1/connections
.
Retrieving a bank connection
To retrieve a bank connection issue a GET
request on the bank connection endpoint and append its ID at the end: https://api.xs2a.com/v1/connections/{$connection-id}
.
Syncing a bank connection
Syncing a bank connection
curl --user api:{$the-bank-users-access-token} \
-X POST \
https://api.xs2a.com/v1/connections/bcn_BnB6mQLsHKZacYvC/sync
POST /v1/connections/bcn_BnB6mQLsHKZacYvC/sync HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Manually syncing a bank connection is only needed when the sync mode is shared or none. If the sync mode for a bank connection is full it will be synced automatically by XS2A once a day.
To sync a bank connection issue a post request on the API endpoint
https://api.xs2a.com/v1/connections/{$connection-id}/sync
The sync call has the following parameters:
Parameter | Type | Description |
---|---|---|
credentials | string | Your part of the shared credentials, if the sync mode is shared. |
force | boolean | If an error occured during syncing, you may force a retry. If the sync_fail_counter goes up to 3 no more syncs are allowed. |
Depending on the state of the bank connection there are two possible responses:
If the sync requires any form of user interaction a structure containing a new
wizard_session_key
will be returned, similar to creating a new bank connection. The HTTP response code will be202
in this case.If the sync process can be executed without any user interaction, the HTTP response code will be
204
and is not returning any content.
Error handling
Any bank connections that are in sync mode full are synced automatically by XS2A. No further steps are needed the turnovers and balance information on the accounts will always be up to date. If a sync process fails for some reason, e.g. the user has changed her password, that the automatic sync will stop. The field sync_message
will contain more information about the error. The field sync_fail_counter
will have the number of subsequent failures. sync_active
will be set to false an the connection will not be synced again.
If the case above the sync can however be forced via the API. See also syncing a bank connection. After 3 failures in a row the bank connection will be disabled and can not be synced again. It will have to be deleted and recreated. The user will have to re-enter her credentials.
Deleting a bank connection
curl --user api:{$the-bank-users-access-token} \
-X DELETE \
https://api.xs2a.com/v1/connections/bcn_A0bkAL1h1POZNKMr
DELETE /v1/connections/bcn_A0bkAL1h1POZNKMr HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
To delete a bank connection, issue a DELETE
request on the bank connections resource URL. The request will only delete the bank connection, not the bank account. This means that if a bank connection is faulty, you can simply delete and recreate it without affecting the list of account. New turnovers will just synchronize into the existing accounts.
The response to a DELETE
request is an 204
status code with an empty response body.
Bank connection events
Payload for
bank_accounts.new_account
andbank_accounts.new_turnovers
{
"id": "ev_vJnkqIQ8f3AMszf2",
"transaction": null,
"type": "bank_accounts.new_turnovers",
"message": "User has new turnovers on a bank account",
"data": {
"bank_user_id": "bus_UcupnDXT1p6WSpWI",
"bank_account_id": "bac_1aQL65xB8ASjvbiJ"
},
"testmode": "0",
"created_at": "2017-12-28 13:44:34",
"object": "xs2a_event"
}
Payload for
bank_accounts.sync_failed
{
"id": "ev_vJnkqIQ8f3AMszf2",
"transaction": null,
"type": "bank_accounts.sync_failed",
"message": "Bank connection synchronization failed.",
"data": {
"id": "bcn_A0bkAL1h1POZNKMr",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"sync_mode": "full",
"sync_active": false,
"sync_message": " Der Login zu Ihrer Bank ist fehlgeschlagen.",
"sync_fail_counter": 2,
"last_synced": "2017-12-27T14:57:59Z",
"testmode": false,
"created_at": "2017-12-27T14:57:59Z",
"object": "bank_connection"
},
"testmode": "0",
"created_at": "2017-12-28 13:44:34",
"object": "xs2a_event"
}
Every event that occurs when syncronizing bank connections is sent out to a webhook URL, that can be configured in the customer cockpit. The following events will be automatically sent to the webhook URLs as they occur:
bank_accounts.new_account
- If a new bank account pops up during syncing that is not yet present in the list of account.bank_accounts.new_turnovers
- If a bank account has gained some new turnovers.bank_accounts.sync_failed
- If a bank connections automatic sync failed for some reason.
The URLs will be called using the POST
method. Unless a successful response code of 200
is seen the URL will be called again up to 30 times in growing time frames. The events are accompanied by a payload that contains information a about what changed.
Bank Accounts
Retrieve a paginated list of all the users bank accounts
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/accounts
GET /v1/api/accounts HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"total": 1,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"next_page_url": null,
"prev_page_url": null,
"from": 1,
"to": 1,
"data": [
{
"id": "bac_c8KYwjexO2iO5AE9",
"holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"joint_account": false,
"transaction_possible": true,
"created_at": "2017-12-06T13:01:01Z",
"object": "bank_account"
}
]
}
Retrieve a bank account
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/accounts/bac_c8KYwjexO2iO5AE9
GET /v1/api/accounts/bac_c8KYwjexO2iO5AE9 HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "bac_c8KYwjexO2iO5AE9",
"holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"joint_account": false,
"transaction_possible": true,
"created_at": "2017-12-06T13:01:01Z",
"object": "bank_account"
}
The endpoint
https://api.xs2a.com/v1/accounts
allows to fetch the list of bank accounts for a user. This endpoint is accessed in the scope a user with a user specific accesst token. Bank accounts are automatically read from bank connections.
A bank account has the following attributes:
Attribute | Type | Description |
---|---|---|
id | string | The ID of the bank account. |
holder | string | The name of the account holder as reported by the bank. |
iban | string | The IBAN of the bank account. |
bic | string | The BIC of the bank account. |
bank_name | string | The name of the bank. |
country_id | string | The country for the bank. |
joint_account | boolean | True, if this account has more that one owner. |
transaction_possible | boolean | True, if this account place payments. |
created_at | string | The creation time of the bank account. |
object | string | The value bank_account . |
Account Balance
Retrieve a bank accounts balance
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/accounts/bac_c8KYwjexO2iO5AE9/balance
GET /v1/api/accounts/bac_c8KYwjexO2iO5AE9/balance HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "bac_c8KYwjexO2iO5AE9",
"available": 3123,
"limit": 1000,
"balance": 2123,
"currency": "EUR",
"date": "2017-12-06T00:00:00Z",
"created_at": "2017-12-06T13:01:01Z",
"object": "bank_account_balance"
}
To retrieve the current balance for an account use the endpoint
https://api.xs2a.com/v1/accounts/{$bank-account-id}/balance
A bank account balance has the following attributes:
Attribute | Type | Description |
---|---|---|
id | string | The ID of the bank account. |
available | number | The available amount. This can be null, if the available amount is not known. |
limit | number | The limit of the account. This can be null, if the limit is not known. |
balance | number | The current account balance. |
currency | string | The bank accounts currency code (3-digit, e.g. EUR). |
date | string | The date the balance was seen on. |
created_at | string | The creation time of the bank account balance object. |
object | string | The value bank_account_balance . |
Account Turnovers
Retrieve a bank accounts turnovers
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/api/accounts/bac_c8KYwjexO2iO5AE9/turnovers
GET /v1/api/accounts/bac_c8KYwjexO2iO5AE9/turnovers HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
{
"id": "bac_c8KYwjexO2iO5AE9",
"turnovers": [
{
"booking_date": "2017-10-08T00:00:00Z",
"amount": -962,
"currency_id": "EUR",
"purpose": [
"SEPA-DAUERAUFTRAG EMPFAENGER HAUSVERWALTUNG",
"MUELLER IBAN DE18701693100100029394 BIC GENODEF1ALX",
"Order-Nr. 00022688654 VERWENDUNGSZWECK MIETE"
],
"counter_iban": "DE18701693100100029394",
"counter_bic": "GENODEF1ALX",
"prebooked": false,
"canceled": false,
"tags": [
"expenditure",
"rent"
]
}
],
"days": 59,
"date": "2017-12-06T00:00:00Z",
"created_at": "2017-12-06T13:01:01Z",
"object": "bank_account_turnovers"
}
To retrieve the list of turnovers for an account use the endpoint
https://api.xs2a.com/v1/accounts/{$bank-account-id}/turnovers
You can use the following GET parameters to filter the turnovers:
Parameter | Type | Required | Description |
---|---|---|---|
from, to | string | Optional | Filter by date. Pass ISO8861 conform dates (yyyy-mm-dd). If you use from without to attribute, it is set to the current date. You will get all turnovers since from |
A turnover list object has the following attributes:
Attribute | Type | Description |
---|---|---|
id | string | The ID of the bank account. |
turnovers | array | The list of turnovers. |
days | number | The number of days requested. |
date | string | The date the turnovers were seen on. |
created_at | string | The creation time of the turnovers object. |
object | string | The value bank_account_turnovers . |
A turnover object inside the list has these attributes:
Attribute | Type | Description |
---|---|---|
booking_date | string | The booking date. |
amount | number | The turnover amount. Negative for expenditures. |
currency_id | string | The currency. |
purpose | array | A string array of purpose lines. The contents vary from bank to bank. |
counter_iban | string | The counter IBAN of the booking. This is not always present. |
counter_bic | string | The counter BIC of the booking. This is not always present. |
counter_holder | string | The counter holder of the booking. This is not always present. |
prebooked | boolean | True, if the turnover has not been booked yet |
canceled | boolean | True, if the turnover has been canceled. |
tags | array | A string array of tags for this turnover. |
Events
curl -X GET -u api:<your-api-key> https://api.xs2a.com/v1/events
GET /v1/events HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Response
{
"total": 66,
"per_page": 15,
"current_page": 1,
"last_page": 5,
"from": 1,
"to": 15,
"data": [
{
"id": "ev_fhDFdPRtECqwOlys",
"transaction": "xv_eR08AnBz7CeBKnzp",
"type": "transaction.created",
"data": {
"account_holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"check_requested": false,
"check_amount": 0,
"check_currency_id": "EUR",
"check_passed": false,
"metadata": null,
"merchant_id": "",
"transaction": "10001-xv-zCTO-xpIT",
"testmode": "1",
"id": "xv_eR08AnBz7CeBKnzp",
"created_at": "2015-05-05 11:47:45",
"object": "xs2a_verification"
},
"testmode": "1",
"created_at": "2015-05-05 11:47:45",
"message": "Transaction xv_eR08AnBz7CeBKnzp created.",
"object": "xs2a_event"
}
]
}
Downloading a single event
curl -X GET -u api:<your-api-key> \
https://api.xs2a.com/v1/events/ev_fhDFdPRtECqwOlys
GET /v1/events/ev_fhDFdPRtECqwOlys HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Response
{
"id": "ev_fhDFdPRtECqwOlys",
"transaction": "xv_eR08AnBz7CeBKnzp",
"type": "transaction.created",
"data": {
"account_holder": "MUSTERMANN, HARTMUT",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"check_requested": false,
"check_amount": 0,
"check_currency_id": "EUR",
"check_passed": false,
"metadata": null,
"merchant_id": "",
"transaction": "10001-xv-zCTO-xpIT",
"testmode": "1",
"id": "xv_eR08AnBz7CeBKnzp",
"created_at": "2015-05-05 11:47:45",
"object": "xs2a_verification"
},
"testmode": "1",
"message": "Transaction xv_eR08AnBz7CeBKnzp created.",
"created_at": "2015-05-05 11:47:45",
"object": "xs2a_event"
}
An event is basically the API representation of a webhook. Every webhook you receive fires an event, that you can process further. You can retrieve a list of all events via the API endpoint v1/events
.
You can also use the following GET parameters to filter the results:
Parameter | Type | Required | Description |
---|---|---|---|
transaction | string | Optional | List all events for single transaction |
type | string | Optional | The type of event e.g. ‘transaction.created’ or 'transaction.updated’ etc. |
from,to | string | Optional | Filter by date. Pass ISO8861 conform dates (yyyy-mm-ddThh:mm:ss-zzzz). The time and timezone portions are optional and may be omitted (e.g yyyy-mm-dd or yyyy-mm-ddThh:mm:ss).. |
since | string | Optional | Filter by date (format yyyy-mm-dd or yyyy-mm-ddThh:mm:ssZ or an ISO8601 conform date. You can also supply date expressions like “-2 weeks” oder “-4 month”). This parameter has been deprecated in favor of from and to . |
The event object is made up of the following fields:
Fieldname | Type | Description |
---|---|---|
id | string(20) | The internal ID of this object. |
transaction | string(19) | The transaction ID this object belongs to. May be null for some events. |
type | string(64) | The type of event. 'transaction.created’ or 'transaction.updated’. |
data | object | The object, that this event relates to. This is usually a transaction object. |
testmode | boolean | 1 for events that belong to test transactions. |
message | string(255) | A human readable message that describes this event. |
created_at | string(19) | The date the event was fired. |
object | string(10) | “xs2a_event” for event objects. |
Deleting Data
All transaction data will get deleted 30 days after they were created.
Transaction data also can be deleted manually by sending a DELETE request for that transaction.
Delete XS2A.Verify request
curl -X DELETE -u api:<your-api-key> \
https://api.xs2a.com/v1/verifications/<transaction-id>
DELETE /v1/verifications/<transaction-id> HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Delete XS2A.Risk request
curl -X DELETE -u api:<your-api-key> \
https://api.xs2a.com/v1/risks/<transaction-id>
DELETE /v1/risks/<transaction-id> HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Delete XS2A.Payment request
curl -X DELETE -u api:<your-api-key> \
https://api.xs2a.com/v1/payments/<transaction-id>
DELETE /v1/payments/<transaction-id> HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Product | Method | uri |
---|---|---|
XS2A.verify | DELETE | /v1/verifications/{transaction-id} |
XS2A.pay | DELETE | /v1/payments/{transaction-id} |
XS2A.risk | DELETE | /v1/risks/{transaction-id} |
Wizard-API
The wizard API allows to avoid the usage of the javascript library xs2a.js
.
Please note that the Wizard API is a feature that needs to be activated for your account in order to use it.
Request
The API endpoint is:
POST https://api.xs2a.com/v1/wizard
There might be different parameters for each POST request for each bank. Therefore there is no explicit listing of all parameters available. However, the following parameters are possible or respectively needed for every request:
Parameter | Type | Required | Description |
---|---|---|---|
wizard_session_key | string | Required | The wizard session key |
action | string | Optional | Valid values are: back (go back one step), switch-login-tabs (switch to another transport), poll (status polling) and change-language (change the language) |
Response
The wizard API is using http status codes to indicate whether the request was successful. If the http status code is
not equal to 200
, the response will only contain the following parameters:
Key | Type | Description |
---|---|---|
code | number | status code to indicate whether the request was successful |
message | string | Descriptive message for the status code |
error | array | Contains the validation errors (only set in case there are any) |
Response to an erroneous request
{
"code": 401,
"message": "Invalid credentials."
}
“Validation failed” response
{
"code": 422,
"message": "Validation failed",
"errors": {
"key": [
"The key field is required."
]
}
}
In all other cases the API will reply with the http status code 200
. The following fields will be set:
Key | Type | Description |
---|---|---|
code | number | The http status code |
message | string | The error message |
error | array | Will be set if an error occurs during the processing of the current step (e.g. the session has expired). If the recoverable flag equals false a new session has to be started. |
polling | object | Indicates if the transaction status needs to be polled (see Polling). |
form | array | Contains the form elements (see Form Elements) |
Response
{
"code": 200,
"message": "ok",
"error": [],
"polling": {},
"form": {
"name": "bank",
"elements": [
{
"type": "select",
"name": "country_id",
"selected": "",
"options": {
"DE": "Deutschland",
},
"validation": "",
"invalid": false,
"failed_validation_rules": "",
"validation_error": ""
},
{
"type": "text",
"name": "bank_code",
"value": "",
"validation": "required",
"invalid": false,
"failed_validation_rules": "",
"validation_error": ""
}
]
}
}
Form Elements
The following elements are possible within each step:
Captcha
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: captcha ) |
name | string | The name of the form element |
data | string | The Base64 encoded image |
value | string | The set value of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Checkbox
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: checkbox ) |
name | string | The name of the form element |
checked | boolean | Indicates whether the checkbox is checked |
label | string | The label of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Flicker
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: flicker ) |
name | string | The name of the form element |
value | string | The set value of the form element |
code | array | The actual flicker image as an array representation (0 = black bar, 1 = white bar) |
label | string | The label of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Help Text
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: help_text ) |
title | string | The title of the form element |
text | string | The text of the form element |
Image
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: image ) |
data | string | The Base64 encoded image |
label | string | The label of the form element |
Multi
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: multi ) |
name | string | The name of the form element |
selected | string | Name of the selected element (value of one of the nested elements) |
elements | array | Array containing the nested elements |
Multi elements
Key | Type | Description |
---|---|---|
label | string | The label of the element |
value | string | The value of the form element |
elements | array | Array containing the nested elements |
Password
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: password ) |
name | string | The name of the form element |
value | string | The set value of the form element |
label | string | The label of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Radio
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: radio ) |
name | string | The name of the form element |
checked | string | Index of the checked element |
options | array | An array of possible options |
label | string | The label of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Select
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: select ) |
name | string | The name of the form element |
selected | string | Index of the selected element |
options | array | An array of possible options |
label | string | The label of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Tabs
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: tabs ) |
name | string | The name of the form element |
tabs | array | An array of possible transports |
label | string | The label of the form element |
selected | string | The selected transport |
Currently tabs will only be used within the login screen if the same bank code is used by different banks (e.g. Frankfurter Sparkasse and 1822direkt).
On the bank transport selection step the transport-ID (e.g.: tab=tra_abcdef3h8J7200aa
) as well as the action
(switch-login-tabs
) need to be provided in the request. Further parameters are not required.
Text
Key | Type | Description |
---|---|---|
type | string | The type of the form element (here: text ) |
name | string | The name of the form element |
value | string | The set value of the form element |
label | string | The label of the form element |
validation | string | List of validation rules, concatenated with a pipe character |
invalid | boolean | Indicates whether the validation of the element failed |
failed_validation_rules | string | A list of failed validation rules (concatenated with a pipe character) |
validation_error | string | The validation error (human readable) |
Validation rules
Rule | Description |
---|---|
alpha_num | Only alpha-numeric characters are allowed |
between:min,max | The field must have a size between min and max |
digits:value | The field must be numeric and must have an exact length of value |
in:value1,value2,… | The field must be included in the given list of values |
min:value | The field must have a minimum value |
max:value | The field must have a maximum value |
required | The field must be present and not empty |
size:value | The field must have a size matching the value |
Polling
Example response
{
"code": 200,
"message": "ok",
"error": [],
"polling": {
"interval": 1000
},
"form": {
"name": "tan",
"elements": [
{
"type": "help_text",
"title": "",
"text": "Bitte geben Sie den Auftrag in Ihrer Banking-App frei."
}
]
}
}
Key | Type | Description |
---|---|---|
interval | integer | The interval in milliseconds |
The polling
attribute indicates whether the transaction status needs to be polled. This is usually the case when
your customer has to approve a payment via the bank’s mobile app.
If polling
is an empty object no action is required. If interval
is set you need to POST a request every interval
milliseconds to the wizard API endpoint providing the wizard session key as well as the parameter action=poll
until
you receive the finish response.
Action
As mentioned above you can provide the action
parameter within your request (e.g. for polling the transaction status).
Here is a list of all possible action
values as well as their description.
Action value | Description |
---|---|
back | Go back one step |
switch-login-tabs | Switch to another transport. Also the parameter tab with the value of the chosen transport ID needs to be present |
poll | Poll the transaction status |
change-language | Change the language. The actual language can be set with the language parameter (de , en and es are supported at the moment) |
“Shared Credentials”
With the Shared Credentials feature you can receive and store the user’s encrypted login credentials in a secure way.
After having logged in successfully the user’s login credentials are encrypted using OpenSSL and the AES-256-CBC cipher. The resulting string is splitted in two parts. The first part will be added to the API’s response, the second part will be stored by us. Please be aware that the credentials will only be included in the response if
- you haven’t provided any credentials in your request or if
- the provided credentials were wrong and the user had to log in manually.
Example response
{
"code": 200,
"message": "ok",
"error": [],
"polling": {},
"form": {
"name": "finish",
"elements": []
},
"additional_data": {
"login_credentials": "crp_T09bO6ba2nSaIsYI|||eyJpdiI6Im...k1M1RXM2xU"
}
}
Whenever your user should be logged in automatically in his bank account without typing in his login credentials, you just need to provide the received credentials part in your POST request for the login form.
curl -X POST -u api:<your-api-key> \
-d credentials=crp_T09bO6ba2nSaIsYI|||eyJpdiI6Im...k1M1RXM2xU
https://api.xs2a.com/v1/wizard
POST /v1/wizard HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Type: application/json
Content-Length: 71
{
"credentials": "crp_T09bO6ba2nSaIsYI|||eyJpdiI6Im...k1M1RXM2xU"
}
Please note that the Shared Credentials feature needs to be activated for your account.
Flow
Initializing the Session
A valid session and a wizard session key are required for the wizard API. Further information on how to create a session is available at XS2A.risk, XS2A.risk-checks as well as XS2A.pay and XS2A.verify.
Initial Request
The initial request requires the key
parameter only.
Initial Request
curl -X POST -u api:<your-api-key> \
-d key=<wizard-session-key>
https://api.xs2a.com/v1/wizard
POST /v1/wizard HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 44
key=<wizard-session-key>
Response
{
"code": 200,
"message": "ok",
"error": [],
"polling": {},
"form": {
"name": "bank",
"elements": [
{
"type": "select",
"name": "country_id",
"selected": "",
"options": {
"DE": "Deutschland",
},
"validation": "",
"invalid": false,
"failed_validation_rules": "",
"validation_error": ""
},
{
"type": "text",
"name": "bank_code",
"value": "",
"validation": "required",
"invalid": false,
"failed_validation_rules": "",
"validation_error": ""
}
]
}
}
Further Steps
Any following requests need to contain at least all required parameters mentioned in the last response (e.g. on the
bank selection page those parameters would be country_id
and bank_code
).
As soon as the wizard has been processed successfully, the last response contains a form element with the name finish
.
The elements
array remains empty. There are no further requests needed and possible.
Finish Response
{
"code": 200,
"message": "ok",
"error": [],
"polling": {},
"form": {
"name": "finish",
"elements": []
}
}
Autocompletion
Autocomplete request
curl -X POST -u api:<your-api-key> \
-d key=<wizard-session-key>
-d action=complete-bankcodes
-d bank_code=<user-input-here>
-d country_id=DE
https://api.xs2a.com/v1/wizard
POST /v1/wizard HTTP/1.1
Host: api.xs2a.com
Authorization: Basic ZzZIWTUyY2VvQ2lselNBYUNzTldoNjdMSG8=
Content-Length: 44
key=<wizard-session-key>
action=complete-bankcodes
bank_code=<user-input-here>
country_id=DE
Bankcodes can be autocompleted.
An autocomplete request needs to be authenticated with a valid wizard_session_id. With that context, we can only display banks, which are suitable for your current use case.
Autocomplete request
Key | Type | Description |
---|---|---|
key | string | current session identifier |
action | string | Needs to be complete-bankcodes |
bank_code | string | Current value of bank_codes input field to autocomplete |
country_id | string | Identifier of current selected country |
Autocomplete response
Autocomplete Response
{
"code": 200,
"message": "ok",
"error": [],
"polling": {},
"form": {
"name": "bank",
"elements": []
},
"autocomplete": {
"name": "bank_code",
"data": [
{
"value": "88888888",
"label": "88888888 [TESTDE88XXX] - Testbank (Teststadt)"
}
]
}
}
A resonse for autocompletion will contain up to 5 suggestions. The data to display will be returned as array in autocomplete.data
.
Client Integration
XS2A offers the possibility of building entire product families based on our “access to the account” concept. It is possible to seamlessly integrate XS2A functionality into your own software or processes. To achieve this flexibility our API is composed of two major components:
- client integration
- server API integration
Client side integration aims towards seamlessly embedding the wizard into your web pages. We offer two methods of integration:
- Direct integration using a Javascript library and a set of CSS themes. Both will be embedded directly into your web interface. The GUI elements are created with DOM-Operations an allow easy styling via CSS.
- The integration by Iframe using another Javascript library. The Iframe will be running on your site and styling is done through the Javascript library. This method of integration is very robust when it comes to layout changes on the XS2A side.
On the server side we offer a REST-API and webhooks for easy integration of your server components.
The following describes the basic steps for a transaction:
- Using the REST-API your server initiates a new session with XS2A. In the response you will receive a unique and only once valid wizard-session-key.
- Using this key you are now able to initiate the Wizard which is seamlessly embedded in your website. The Wizard offers various interaction possibilities during the transaction.
- While the customer is using our Wizard, you are able to customize and individualize the interaction through various JavaScript callbacks.
- After the customer has finished the transaction and interaction with our Wizard, you will receive a client JavaScript callback and also a server side webhook will be executed. Your application will be notified on both the client and server side that a transaction has finished.
Javascript and CSS
Embed both JavaScript and CSS libraries
<script src="https://api.xs2a.com/xs2a.js"></script>
<link rel="stylesheet" href="https://api.xs2a.com/xs2a.css">
You will have to embed both of our JavaScript and CSS libraries into your website.
Both libraries can be embedded into the <head>
section of your website. We suggest to hotlink
both files directly from our XS2A server. This will ensure you will always use the latest build of both files.
The xs2a.js
will register a new global JavaScript object xs2a
. Use this global object to interact with
XS2A forms. You will also have to include a container element into your website.
Container element
<div id="XS2A-Form" data-xs2a="<your-wizard-session-key-here>"></div>
The XS2A Wizard will be rendered within the container element. We strongly recommend to leave the id attribute
XS2A-Form
unchanged. Our CSS rules depend on it. Please see also CSS Styleguide.
If you do include our container element within a form-tag, pressing the enter key might accidentally submit data to your server. There is also the possibility that wrongfully entered login information will be prefilled by the browser.
Initializing JavaScript
xs2a.init();
Initialize our JavaScript by calling the init()-method. The javascript will then connect to our servers and start the XS2A-Wizard inside of the container element.
If you followed our instructions for including our JavaScript file the global xs2a object will be available
after the <script>
tag. The xs2a object implements the following methods:
xs2a.init()
xs2a.init()
initializes the XS2A object on the current page. It will look for an HTML element with a
data-xs2a
attribute, e.g.:
<div class="XS2A-Form" data-xs2a="<wizard-session-key>"></div>
The XS2A Wizard will be rendered in the described element. It is considered the “Wizard Element”.
xs2a.finish(function)
xs2a.finish()
Is used to register a callback function which will be called after the transaction has finished.
You must provide a xs2a-finish()
callback, because after a finished transaction the customer needs
to be redirect.
Redirect example
xs2a.finish(function() {
window.location.href = 'http://<your-success-link>';
});
xs2a.abort(function)
xs2a.abort()
The callback will be executed in case the customer decides to abort the current transaction.
We suggest to redirect the customer accordingly. The abort()
callback must be provided.
Abort example
xs2a.abort(function() {
// Will be executed in case the customer aborts the transaction
});
xs2a.error(function)
xs2a.error(function(errorCode, messages, recoverable))
The callback will be executed in case an error occurs during the transaction.
Error example
xs2a.error(function(errorCode, messages, recoverable) {
// Will be executed in case an error occurs during transaction
});
Code | Description |
---|---|
login_failed | Login to bank failed (e.g. invalid login credentials) |
session_timeout | The customer’s session has timed out. |
tan_failed | User entered invalid TAN |
tech_error | An unknown or unspecified error occurred |
testmode_error | An error occurred using testmode settings |
trans_not_possible | A transaction is not possible for various reasons |
validation_failed | Validation error (e.g. entered letters instead of numbers) |
recoverable
indicates whether the error results in an abortion of the transaction. If
recoverable
equals false the transaction is aborted.
xs2a.bank(function)
xs2a.bank()
Allows you to register a function which will be executed before a bank selection page will be shown. For example, you can use this callback to provide some custom information on this page.
Blank example
xs2a.bank(function() {
document.getElementById('your-text').style.display = 'block';
});
xs2a.login(function)
xs2a.login()
Callback can be registered which will be executed before the bank login page will be displayed. See also xs2a.bank(function).
xs2a.account(function)
xs2a.account()
Callback which will be executed before the bank account selection page will be displayed. See also xs2a.bank(function).
xs2a.tan(function)
xs2a.tan()
Callback can be registered which will be executed before the bank enter tan page will be displayed. See also xs2a.bank(function).
xs2a.render(function)
xs2a.render()
Callback can be registered which will be executed every time a new form is displayed. So basically it will be executed before every step. See also xs2a.bank(function).
xs2a.abortTransaction()
Abort transaction example
<a href="#" id="abort">Abort transaction</a>
<script>
document.getElementById('abort').onclick = function() {
xs2a.abortTransaction();
};
</script>
xs2a.abortTransaction()
makes it possible to abort the current transaction manually.
If it fits your use case you may simply add an Abort-Link or Button to your Form and register an
event listener, that calls xs2a.abortTransaction()
. This can be done like that:
The callback that you registered in xs2a.abort()
will also be executed within this call. There is no
need to trigger it yourself.
xs2a.lang()
Set language example
<select id="lang">
<option>de</option>
<option>en</option>
</select>
<script>
$('#lang').change(function() {
var language = $('#lang').val();
// set the language for the xs2a wizard
xs2a.lang(language);
// set the language for your app
document.location.href = "..."
});
</script>
xs2a.lang()
allows to get or set the language during a transaction. If no parameter is passed
xs2a.lang()
simple returns the current language which may be de
or en
. If a parameter is
passed, the form will be redisplayed with the new language set. The method will again return the
language that was actually set.
Please note that setting the language is only allowed if the user is not yet logged in to his or her bank. If the user is already logged in the language will not be changeable.
Please also note that bank messages will not always be translated. For example banks, used via HBCI or banks that do not allow to switch the language will be served in German or in the default language provided by the bank.
xs2a.configure()
It is possible to set some configuration options, to alter the default behavior of the wizard.
This method needs to be called before init().
disable login credentials validation “`javascript xs2a.configure({ ‘validate-login-credentials’: false, 'autocomplete-suggestions’: 10 });
xs2a.init(); ”`
name | default | description |
---|---|---|
validate-login-credentials | true | A warning will be displayed, if the user enters a password which is 4 characters or less. |
autocomplete-suggestions | 5 | Set the amont of autocomplete suggestions. (1-20) |
CSS
We strongly suggest to include our base CSS directly from our servers:
<link rel="stylesheet" href="https://api.xs2a.com/xs2a.css">
The XS2A form embeds itself seamlessly into your website using DOM operations. This enables you to define your own custom CSS rules and customize the look and feel to fit your needs. You can even define your own themes. We would like to give you some basic guidelines for creating your own themes.
The CSS rules define the positioning of elements within the XS2A container. For other
formatting needs you can use themes. You can also defined custom themes in combination with xs2a.css
.
We currently offer the following themes:
<link rel="stylesheet" href="https://api.xs2a.com/xs2a-green-gray.css">
<link rel="stylesheet" href="https://api.xs2a.com/xs2a-dark-flat.css">
<link rel="stylesheet" href="https://api.xs2a.com/xs2a-light-blue.css">
Custom Themes
When creating your own themes, the easiest way is to use the base CSS xs2a.css
theme as a basis for
your own design.
If you create your own theme, we recommend to follow these guidelines:
- Build upon the base CSS. This will ensure you correct styling in case future HTML markup changes occur. Also the positioning rules are always the latest.
- Build upon one of our predefined themes. The rules in our predefined themes are styled in a way that even if future changes to the markup occur, it will still be the correct elements that will be changed. This increases the robustness of your integration.
- Add a style directly to elements. The best way is to define a style for the elements as directly as possible. Use simple selectors which should not make assumptions about the HTML structure.
Please keep in mind that we can not provide support for themes which do not use our base CSS as a basis or are not based on one of our standard themes.
Extending the xs2a forms
Extending the bank code entry form by appending an email text input
xs2a.extend('bank', function(form) {
form.text('email', 'E-Mail', '', '', ['required', 'email'], form.APPEND);
form.description('To proceed you need to enter a valid email address.', form.APPEND);
});
xs2a.init();
Extending the login form by appending a required checkbox
xs2a.extend('login', function(form) {
form.paragraph('Custom title', 'Custom text', form.PREPEND);
form.checkbox('my_policy', 'I accept this policy.', true, form.APPEND);
form.description('To proceed you need accept this policy.', form.APPEND);
});
xs2a.init();
Extending both forms with a custom message
xs2a.extend('bank', function(form) {
form.paragraph('Hallo', 'This is a custom message', form.PREPEND);
});
xs2a.extend('login', function(form) {
form.paragraph('Hallo', 'This is a custom message', form.PREPEND);
});
xs2a.init();
The XS2A platform also offers the ability to extend its forms with your own custom fields. That might be useful if you want to ask for some additional information during the transaction. Additional information may be things like email addresses or asking the user to confirm additional checkboxes.
The two forms that can be extended are the bank code entry form and the login form. You may add custom form elements by appending or prepending them to the existing form. The custom form elements that you can add via the API are:
- Paragraphs - Text paragraphs that can optionally contain a title.
- Descriptions - Textual descriptions for input fields.
- Checkboxes
- Text inputs
To extend the forms the global xs2a
object provides the method xs2a.extend
. This method receives
a callback as its first argument. This callback is used to work with a FormBuilder
that is
passed to the callback. The xs2a.extend
method should be called before xs2a.init
.
The form builder passed to the callback has the following methods:
form.paragraph()
form.paragraph(title, text, where)
Adds a paragraph to the form.
Parameter | Type | Description |
---|---|---|
title | string | The title of the paragraph (optional). |
text | string | The text of the paragraph (optional). |
where | string | Where to put the paragraph. One of form.APPEND or form.PREPEND. (optional) |
form.description()
form.description(text, where)
Adds a description text to the form.
Parameter | Type | Description |
---|---|---|
text | string | The text of the paragraph. |
where | string | Where to put the paragraph. One of form.APPEND or form.PREPEND. (optional) |
form.checkbox()
form.checkbox(name, label, required, where)
Adds a checkbox input to the form.
Parameter | Type | Description |
---|---|---|
name | string | The name of the checkbox input. |
label | string | The label of the checkbox input. |
required | boolean | True, if the user has to check this box. |
where | string | Where to put the paragraph. One of form.APPEND or form.PREPEND. (optional) |
form.text()
form.text(name, label, value, placeholder, validation, where)
Adds a text input to the form.
Parameter | Type | Description |
---|---|---|
name | string | The name of the input. |
label | string | The label of the input. |
value | string | Prefill this input. (optional) |
placeholder | string | The placeholder text for this input. (optional) |
validation | array | An array of validation rules. Allowed validation rules are required , email , numeric and alpha_num . (optional) |
where | string | Where to put the paragraph. One of form.APPEND or form.PREPEND. (optional) |
The values entered will be in the
metadata
attribute
{
"id": "xv_hd84kg9zns53lvh1",
"transaction": "10001-xv-abcd-abcd",
"object": "xs2a_verification",
"account_holder": "Account Holder",
"iban": "DE62888888880012345678",
"bic": "TESTDE88XXX",
"bank_name": "Testbank",
"country_id": "DE",
"check_requested": true,
"check_amount": "100.0",
"check_currency_id": "EUR",
"check_passed": true,
"testmode": true,
"metadata": {
"email": "mail@customer.com",
"my_policy": "on"
},
"merchant_id": "",
"created_at": "2014-03-23 15:55:54"
}
You receive the values, that the XS2A platform collected for you in the metadata
attribute of your transaction object, when you finally fetch it via the JSON API.
See the API description for the product you are using for more details on how to get the transaction object after a transaction is finished.
Links, modal dialogs and tooltips
You may also include links, modal dialogs and/or tooltips in the provided text.
To include a link use the following syntax:
Text with a link [<name>|link::<url>]
A modal dialog can be included with:
Text with a modal dialog [<name>|dialog::<text>]
You can include a tooltip using the following syntax:
Text with a tooltip [tooltip|<text>]
Iframe
Embed JavaScript library into your page
<script type="text/javascript" src="https://api.xs2a.com/xs2aframe.js">
</script>
Container element
<div id="XS2A-Form" data-xs2a="<wizard-session-key>"></div>
The JavaScript library can either be added to the <head>
or the <body>
region of you website.
It is strongly recommended to hotlink this file so that you always use the latest available version.
The script registers the global object xs2aframe
, that can be used to further interact with the wizard.
You will also have to include a container element into your website.
xs2a.init();
Initialize our JavaScript by calling the init()-method. The javascript will then connect to our servers and start the XS2A-Wizard inside of the container element.
Example integration
<!DOCTYPE html>
<html>
<head lang="en">
<title>xs2a</title>
</head>
<body>
<div id="xs2a-form" data-xs2a="KoA6ZwdTYeqSIvv6QpBf0VU9bWVnf8zmguNdGRpK">
</div>
<script src="https://api.xs2a.com/xs2aframe.js" type="text/javascript">
</script>
<script type="text/javascript">
xs2aframe.init();
</script>
</body>
</html>
xs2aframe.init()
xs2aframe.init()
Initializes the xs2aframe-object and the iframe is inserted into
the container element (e.g. the div
-element).
xs2aframe.finish()
xs2aframe.finish()
Register a callback function that will be executed, once the transaction was executed successfully. This callback function must be provided, so that the user is properly redirected after the transaction is completed.
Redirect example
xs2aframe.finish(function() {
window.location.href = "https://<success_url>";
});
xs2aframe.abort()
xs2aframe.abort()
Register a callback function that is executed when a transaction is
canceled by the user, e.g. clicking the abort button. Just like the finish()
callback this
callback must be defined.
xs2aframe.render()
xs2aframe.render()
Callback which will be executed every time a new form is rendered inside the wizard.
xs2aframe.bank()
xs2aframe.bank()
Callback function that will be executed when the bank selection page is shown. Providers may implement this callback to display some information they might consider helpful for the user.
xs2aframe.login()
xs2aframe.login()
Callback function that will be executed when the login to the bank is displayed.
xs2aframe.account()
xs2aframe.account()
Callback which will be executed when the account selection is displayed to the user. Note that this step only occurs if the user has more than one account.
xs2aframe.tan()
xs2aframe.tan()
Callback which is executed when the TAN input page is displayed.
Customization
The xs2aframe object makes it possible to change the looks of the XS2A wizard according to your requirements.
The CSS ruleset that is loaded by default only defines the positioning of the elements in the wizard. By using one of the predefined themes you can manipulate the coloring of the forms or by using custom style rules using the styling API.
Themes
Changing default theme
xs2aframe.theme("xs2a-green-gray");
Currently there are three predefined themes, that you can build upon:
- xs2a-green-gray
- xs2a-dark-flat
- xs2a-light-blue
By calling the theme()
method you can use one of the mentioned themes.
Customized Themes
To make individual customizations of the forms possible, you have the style
method
in place. Currently you can make customizations in the following groups:
Group | description |
---|---|
global | global settings (e.g. background or font colors) |
textInput | all <input> elements |
buttonForward | the button that lead to the next step |
buttonBack | the back button |
buttonAbort | the abort button |
buttonDisabled | a disabled button |
warning | a box with warning texts |
info | a box with an info text |
error | a box that contains an error message |
You can set the following attributes:
Name | Possible values |
---|---|
backgroundColor | #ff0000, transparent, initial, inherit |
color | #ff0000, transparent, initial, inherit |
margin | 1px 5px, 0.5em, -5pt, 10%, auto, inherit |
padding | 1px 5px, 0.5em, -5pt, 10%, auto, inherit |
border | 5px dotted |
borderRadius | 2px 1px 4px / 0.5em 30%; |
textAlign | left, right, center, justify, initial, inherit |
textDecoration | none, underline, overline, line-through, initial, inherit |
fontFamily | “Times New Roman”, Times, serif; Arial, sans-serif; |
Custom styling based on one of the themes:
xs2aframe.theme("xs2a-green-gray");
xs2aframe.style({
global: {
color: "#000",
backgroundColor: "#cacaca"
},
buttonForward: {
color: "fff",
backgroundColor: "#00ff00",
border: "1px solid #00ff44",
borderRadius: "4px"
},
warning: {
margin: 4px 2px 4px 2px,
padding: 8px,
backgroundColor: "ffa500"
}
});
Events and Webhook
Example system call to your URL
{
"id": "ev_kdhwWdkshflL237SdkDQ",
"object": "xs2a_event",
"type": "transaction.created",
"testmode": true,
"data": {
},
"created_at": "2014-03-23 14:00:03"
}
An event is basically anything that can happen with your XS2A account, e.g. creating a transaction, matching of a transaction and the like. Also includes things like changing your account password.
A webhook ist just a URL which will be called whenever an event has happened.
You can view events within our admin application or via API. Webhook URLs can be
added, edited or deleted. You can enter up to three URLs. All URLs will be called via POST
.
Using HTTPs is required for all webhooks, yet the certificate may be a self signed one.
The field data will have event dependent information. Currently we support the following events:
Event | Description |
---|---|
transaction.created | A XS2A transaction has been created. Transaction data will be within the data . |
transaction.updated | Transactions might get an updated notification. The updated transaction data will be within the data . |
account.password_changed | Account password has been changed. The field data will be empty. |
A connection error or a HTTP status code > 400 will be interpreted by the XS2A platform as a failed webhook. In this case the webhook will keep retrying to call your URL again (with an increasing time span between multiple tries).
The first five tries will be made within the first minute. All other tries will be within an increased time span. After a total of 40 tries the webhook will be killed.
Webhook Signature
Example signed weebhook call to your URL
POST /your-webhook-url HTTP/1.1
Host: yourserver.com
X-Payload-Signature: v1=6754b105f95c0cd9c544701451df7ffeebcb4ff7f17b64f75239502b27b1d8ab
Content-Type: application/json
Content-Length: 56
{
"id": "ev_kdhwWdkshflL237SdkDQ",
"object": "xs2a_event",
"type": "transaction.created",
"testmode": true,
"data": {
},
"created_at": "2014-03-23 14:00:03"
}
Our webhooks are singed. Its recommended to check signature for validity.
The signature will be sent in HTTP-Header X-Payload-Signature
.
You can find your shared secret on your webhook configuration page.
Versioning
To maintain a backward compatibility, we maintain a versioned signature in our HTTP-Header.
The format for multiple versions is as followed: v1=hashv1; v2=hashv2
Checking Signatures for validity
To check a signature for validity you need to calculate and compare the hash for your corresponding version.
v1
In this version, you need to create a hash over the entire content of the webhook and create a Hash Message Authentication Code (HMAC) with the following settings:
Algorithm: SHA256
Payload: Entire payload (including whitespaces)
Secret: Shared secret. This can be found on your webhook configuration page.
Example
Message | Secret | Signature |
---|---|---|
Hello World! |
secret_password |
v1=faeffaa195ee7b044d20f034b5cf7ed1309c9e1f043836a65227d55be6452af2 |
Testbank
For testing and integration purposes we offer a Testbank. While using the Testbank, no real transactions will be made.
The Testbank allows you to try out various ways the Wizard and other components can or will behave.
Please use 88888888 as bank code or use BIC TESTDE88XXX for a German Testbank. Use 88888 as bank code or use BIC TESTAT88XXX for an Austrian Testbank.
Display of wizard tabs can be forced by using the bank code 88888889 in combination with a test API key.
In case the chosen product requires recipient information, entering almost any data is fine as long it conforms to the basic validation rules set by the chosen product.
You can use the following options with both banks as PIN in the login step to force certain behaviors:
PIN | Description |
---|---|
accounts | Displays the account selection step with more than one account available. |
autosubmit | Display a form that simulates waiting for authorization from an external source, e.g. customer uses a token device. |
business | Returns business accounts instead of private accounts by returning business accounts and turnovers. |
config | Allows you to configure some custom settings for testing various settings, e.g. turnover types, holder names etc. |
forms | Allows you to choose from some prepared forms with various UI elements of the Wizard. |
next | Displays a login next step |
no-account | A transaction without a valid account type. |
no-standing-orders | The chosen account has no standing orders. |
no-turnovers | No turnovers. |
negative-balance | A transaction with a negative account balance. |
slow | Slows down the transaction considerably. |
with-chargeback | Generates a turnover that indicates a chargeback. |
with-credit-card | Adds a credit card to the list of accounts |
with-seizure | Generates an account under seizure. |
wrong | Provokes a login error. |
iban: |
Add a custom account, with an specific iban to the list of available accounts. |
To simulate a wrong TAN attempt, please enter WRONG as TAN.
If you provide an account number or IBAN in the initial call, the customer will not be able to choose a different account, even if there are more accounts available to chose from. If the given IBAN is not in the customer list of accounts, the transaction will be aborted.
In case you want to test pinned account numbers or IBANs, the German Testbank will return the following accounts:
IBAN | Account Number | Bank Code | Description | Transaction possible |
---|---|---|---|---|
DE62888888880012345678 | 12345678 | 88888888 | Girokonto | Yes |
DE04888888880087654321 | 87654321 | 88888888 | Extra-Konto | No |
If you use the login PIN accounts the German Testbank will return additional accounts:
IBAN | Account Number | Bank Code | Description | Transaction possible |
---|---|---|---|---|
DE35888888880012345679 | 12345679 | 88888888 | Girokonto Plus | Yes |
DE93888888880043218765 | 43218765 | 88888888 | Kontokorrent | Yes |
In case you want to test pinned account numbers or IBANs, the Austrian Testbank will return the following accounts:
IBAN | Account Number | Bank Code | Description | Transaction possible |
---|---|---|---|---|
AT248888800012345678 | 12345678 | 88888 | Girokonto | Yes |
AT638888800087654321 | 87654321 | 88888 | Sparkonto | No |
If you use the login PIN accounts the Austrian Testbank will return additional accounts:
IBAN | Account Number | Bank Code | Description | Transaction possible |
---|---|---|---|---|
AT948888800012345679 | 12345679 | 88888 | Girokonto Plus | Yes |
AT558888800043218765 | 43218765 | 88888 | Kontokorrent | Yes |
Diagrams
This chapter shows a couple of sequence diagrams for common scenarios. The diagrams are quite detailed and designed to further your understanding of how the involved parties interact.
XS2A.pay with JS widget
This diagram shows a standard integration of the JS widget for a payment initiation service.
XS2A.risk with wizard API
This diagram shows a standard integration of the XS2A.risk API using the wizard API.
XS2A.risk with JS widget
This diagram shows a standard integration of the XS2A.risk API using the Javascript widget.