# Quick start

Welcome to the [Finqware](https://www.finqware.com) API!

This beta phase is about learning and testing various APIs with medium & large businesses willing to integrate Open Banking into their business workflows.

1. Contact us and register your company
2. We'll provide access to our developer's [portal](https://beta.developers.finqware.com)
3. Use the dev portal to create tenant apps & API keys, browse through Finqware skills and test them.


# Skills

#### Concept

Open Banking is about *opening* access for businesses to create value on top of financial services provided via APIs.

Each API that we integrate into our middleware is a `skill`. Examples: an account information API from Bank X is a skill, a payment initiation service from Bank Y is another skill.

With the initial releases, we'll focus on three skill types: account information, payment initiation and marketplace. As a roadmap item we're planning to introduce more utility such as *customer care* and skills related to *resource management*.

Each skill comes in two flavors: production and sandbox. Test & dev tenants will use sandbox skills.

#### Account information

These skills are mainly based on PSD2 AISP APIs from various banks.

Use cases: wallet applications or enterprise systems that need to query for bank accounts and transaction reports.

#### Payment initiation

Initially based on PSD2 PISP APIs from various banks.

Use cases: merchants willing to accept payments through a direct account-to-account transfer bypassing classic payment schemes.

#### Marketplace

Based on custom connectors that we're building with our partner servicers.

Use cases: marketplaces interested in selling financial products without the hassle of a direct integration with banks, insurance providers etc.


# Servicers

A `servicer` is a partner company registered with Finqware.

It may be a bank or an insurance company providing skills into the middleware, or a fintech that consumes the Finqware API.

Or even both: a bank may be providing its own APIs into the middleware and at the same time it may implement a multi-banking experience on top of Finqware.

From a Finqware API consumer standpoint, a servicer may register multiple `tenant` apps.

A servicer has a number of developers/users with credentials on our developer's portal.


# Tenants

A `tenant` is your software, consuming the Finqware API. It usually has two components:

* a client-side application (eg: a mobile and/or a web front-end)
* a server. This is where you run the business logic, the user database etc.

It's important to make a clear distinction between the two. There are specific data items (i.e. tokens, secrets) that you can safely store in your client app, and others that we recommend to be used only in a server-to-Finqware communication.

A servicer may register multiple tenant apps for different business cases or just for technical reasons (eg: test & prod apps).

For a granular access control and reporting, each tenant is required to register the list of skills it connects to.


# Security model

The Finqware API is protected by a number of keys and tokens.

It is important to follow the best practice around where it's safe to store/use them. You can make an API call from a web application using the `client_id`, but use an `access_token` only from your server-side code. Currently, a generally accepted opinion among security experts is that you cannot safely store secrets in a client application (web or mobile code).

Besides the API keys listed here, the **/v1s** is an extra secured endpoint (recommended for production) that requires message digest & signing - please check the details [here](/dev-guide/signing-api-requests).

| Token/key        | Client | Description                                                                  |
| ---------------- | ------ | ---------------------------------------------------------------------------- |
| client\_id       | yes    | An identifier for a tenant app                                               |
| client\_secret   | no     | A secret generated for each tenant app                                       |
| client\_app\_key | yes    | Used to initate a user session                                               |
| temp\_token      | yes    | A temporary token that can be exchanged for an access\_token                 |
| credentials\_id  | no     | A consent record that points to user data (eg: a bank account, an insurance) |
| access\_token    | no     | A permanent token authorizing access to user data                            |


# Tenant-level elements

Each tenant application will have three security elements associated with it:

* client\_id
* client\_secret
* client\_app\_key

They do not expire, but can be refreshed using the developer's portal.

As you'll notice in the developer's guide, a user session ends with receiving a `temp_token`. The reason we're not sending the `access_token` directly is that we designed the session flow to be developed entirely in a web/mobile context. This choice also facilitates the future development of client SDKs. Hence the middleware returns a temporary token that needs to be sent to your backend first and then exchanged for the final `access_token` via a server-to-Finqware API call.

As a side note: we're also considering introducing a callback endpoint as an option. Following the end of a session, Finqware would call an API endpoint provided by your server for the token exchange.


# User-level elements

Taking a user through a session is about obtaining consent to access their data (eg: an existing bank account), or creating new value for that user (eg: selling a new insurance). In both cases, there is at least one target object created at the middleware level.

Finqware does not store data that identifies the owner, but we return a `credentials_id` that represents your acccess point to these objects.

Practical example: for an account information skill backed by PSD2 AISP, a user may give their consent to access three bank accounts. In this case, your generated `credentials_id` will point to these three objects.

An API call where `credentials_id` is specified, needs to be authorized by its respective `acccess_token`.

Your user may have multiple pairs of \[`credentials_id`, `access_token`] depending on how many resources they decide to access through your app. Plan and design your user database considering this aspect.

![](/files/uhU3rKMDxU98Emp8hkl6)


# Intro

This section is for tenant app developers who want to implement the base API (REST & GraphQL). We'll also make SDK's available, but the API endpoints will always remain open for those who need maximum flexibility.

Implementing Finqware skills is always centered around the **end-user** - that being the individual or institution who owns the data queried through the middleware. As a tenant app developer, you're implementing two aspects:

1. A conversational UX that takes the user through a number of action steps in order to get access to the data. This is a web or native-mobile UI that takes your user through an onboarding experience.
2. A Backend/server piece that consumes data the user has already consented for in the previous step.


# User onboarding

The first thing to focus on is to offer your user a smooth onboarding experience. You may design a classic wizard with a step-by-step approach or have a more inovative approach like chatbot or voice-based UIs.

The Sessions API helps you implement such a UI. A session is very similar to what most of us know from web programming: an ordered sequence of steps that share the same state. Although this is a unified developer experience, each skill may have particular steps to implement.

Practical examples:

* getting the user consent for an account information skill is a one-step session (i.e. trigger the strong customer authentication process)
* selling a bank deposit product takes the user through multiple steps where the user may be required to submit information and upload data in separate steps due to inter-step dependencies.

As we integrate more skills into the middleware, we'll be documenting the required steps for each case. The Sessions API is generic enough to support complex conversational UIs that involve multiple iterations, uploads, synchronous and asynchronous communication (eg: cases where the online session might be interrupted due to an offline verification).

This diagram is an example of a three-step session, where the first two steps have attachments (uploads).

![](/files/icqPa2Q5yGg6lFvHV945)


# Detailed flow

An oboarding session is triggered by a `HTTP POST` to the `/sessions` endpoint. It has to include three elements:

* `client_id`: identifies your tenant application
* `client_app_key`: authorizes the call (safe to be used from a client app)
* `skill`: which skill you're starting the onboarding session for. This is taken from the skills catalog published and updated on our docs.

```javascript
{
  "client_id": "{{client_id}}",
  "client_app_key": "{{client_app_key}}",
  "skill": "xyz_aisp_sbx_#1.0"
}
```

Following a successfull call, you will receive a message including:

* a `session_id`: identifies the newly created session. You will use this to submit subsequent steps.
* a `nonce`: a temporary token safe to be used from a client app. You will use this to submit data in the next iteration - that would be step #1 into your session. Currently the nonce expires in 30 minutes.
* a `status`: an informative message

```javascript
{
  "nonce": "F3YXJlCjAwMT...ToxNToxNS41OTE5Nz",
  "session_id": "7489fe74-...-cd5e05c0fc4b",
  "status": "SESSION_CREATED"
}
```

Now that the session is created, you can start submitting data specific to each skill. At each iteration you specify the `step` and provide the `nonce` retrieved from the previous one. In a multi-step session, at each step submission, the response message will include a `step_id` and the `nonce` for the next step.

Use the `/sessions/{session_id}/steps` endpoint to submit data for a specific step.

```javascript
{
  "client_id": "{{client_id}}",
  "nonce": "{{nonce}}",
  "skill": "xyz_sbx_#3.0",
  "step": "product_form",
  "data": {
    "value": "100000",
    "currency": "EUR",
    "period": "12"
  }
}
```

At certain steps, a skill might require specific uploads. An example would be an onboarding session for a credit card product. The KYC (know your customer) flow asks for personal data, ID upload and photo/selfies.

Use the `/steps/{step_id}/upload` endpoint to submit uploads for a specific step.

![](/files/VztYrKZDkajZIGTrg7LB)

In the above diagram please notice the moments where `nonce` for each step and the `temp_token` are generated. The nonce to be used for any API call related to step #1 is generated when the session is initialized. The nonce to be used for any API call related to step #2 is generated when step #1 data is submitted.

The temp\_token is generated when you submit data with the last step - in the example above, the session has two steps, hence it's generated with Step #2. This marks the end of a successful user session: user consent has been given or the product onboarding was done without any issue.

This is an important point in this flow, as you need to make the switch to the server-side. The switch is made by sending the `temp_token` to your backend server. This is where you call the `/token` endpoint to exchange it for an `access_token` along with the `credentials_id` that points to the newly created object/s.

![](/files/CoHzOWQ9akz9gdZLps95)

The call to `/token` is authenticated by using the `client_id` and `client_secret`. The `access_token` plus the `credentials_id` need to be stored by your backend along with the end-user data.


# Consuming data

Having the `access_token` and the `credentials_id` for a certain resource generated with the flow above, you can now start querying the data.

This is specific for each skill. An account information skill would be used by querying the `/accounts` and `/transactions` API endpoints. We're also planning to release the GrapqhQL endpoints, including support for realtime subscriptions - currently in internal testing phase.

At this stage, all the API calls should be done by your tenant's backend, authenticated with the tenant's `client_id` and `client_secret`.


# About caching

## Overview

Certain skills, such as account-information, require data to be retrieved as fast as possible by your tenant apps. In order to make this data available with no restrictions and aim for realtime, Finqware builds a temporary data cache that stores & indexes relevant data (eg: accounts, transactions).

### Parameters

This data cache is governed by two parameters configured at tenant-skill level: when you configure your tenant app with a certain skill, you may update these parameters:

* **consent\_duration**: how long (in minutes) until the consent (pointed by credentials\_id) is marked as expired and can no longer be used. By default this is 90 days (129600 minutes).
* **cache\_max\_data\_retention**: the maximum amount of time data is kept in the cache. By default this is 120 days (172800 minutes).

### Force consent expiration & data deletion

The [Consents API](https://github.com/finqware/gitbook-public-docs/blob/main/dev-guide/consuming-data/broken-reference/README.md) allows a tenant app to delete a specific consent (pointed by credentials\_id) by using the delete operation.

Optionally, you may specify the **pcd\_data\_retention** parameter (pcd stands for *post consent delete*) that would overwrite the cache\_max\_data\_retention *for that particular consent only*. Say for example you want to delete the cached data immediately at the same time the consent is deleted - you would specify a value of 0 and Finqware will permanently delete the cached data for that consent as soon as possible.

If you do not specify a value for the **pcd\_data\_retention** parameter, cached data will be deleted as usual, according to the **cache\_max\_data\_retention**.

### FAQ

How often does the data expiration jobs run?

\*\* **\_**&#x41;:\*\* Every two hours at the moment.\_

What exactly is the data expiration job doing?

\_ **A**: This is a background job that automatically expires consent objects based on the **consent\_duration** parameter and permanently removes data from the cache based on the **cache\_max\_data\_retention** parameter.\_

What happens when a **credentials\_id** is automatically marked as expired?

***A:** API calls that require the credentials\_id will return a 401 error (unauthorized / inactive\_credentials).*

Are you planning to have a parameter to bypass entirely the Finqware cache and make a request back-to-back with the 3rd party API?

*\*\* A: \*\*Yes, on the roadmap.*

Are you planning to have an option to encrypt the cache with an encryption key provided by the tenant app?

*\*\* A: \*\*Yes, on the roadmap. Note that this option will make indexing data impossible and hence queries using filtering will not work.*


# Designing a tenant app

As mentioned before, building an application on top of Finqware means **in general** that you have to build a front-end (web/mobile) and a backend. It is unsafe to build a client-only app unless it will run on trusted devices.

It will be possible to build your app entirely on the backend though. This is targeted to enterprise applications.

The example architecture presented here is following a pattern mainly used by native mobile apps and web applications that render data inside the browser:

* the back-end handles the main database, business logic, sensitive information, communication with 3rd party APIs (eg: Finqware) etc. It also exposes a private API (eg: REST or GraphQL) that is available only to a known front-end. It may be developed in any popular language (eg: Java, PHP, NodeJS etc).
* the front-end is an application developed with Android, Swift, JavaScript (React, Angular etc). It only consumes data from its own backend. It initiates external API calls only in exceptional situations. An example Js/React app is running at [https://play.finqware.com/](https://play.finqware.com).

NOTE: *Classic architectures based on server-side rendering (PHP, JSP etc) are perfectly possible but here we chose a more generic example that applies to both mobile & web front-end types. The data model and state management still apply.*

## What the Finqware API is not

We do not offer at the moment a backend-less solution. That means there is work to be done in your own backend:

* user management
* extra processing of data (eg: custom data transformations)
* caching for improving your SLAs


# The back-end

Building a data model.

### A simple UML design for the database

![](/files/maZxJqVYnZq16xPTsTvs)

### Data model

Central to this design is the `users` table. This is where you store end-user identities for authentication.

`Skills` table: an inventory of skills (Bank connectors) that were registered by our tenant app. There is a many-to-many relation with `users` - a user may choose to connect to many Banks; a skill me be used by many users. This table is maintained manually because it contains mostly static information. Whenever we configure a new skill to the tenant app, we add a new record here, making sure you have a `Servicer` record first (see below). Once the record is added, it should show up in the user's GUI as a new option to connect.

`Accounts, Balances, Transactions`tables: a cache of data coming from Finqware. ***Note***: Finqware strives to be highly available but having your own cache for a better service level is never a bad idea.

`Servicers` table: each Bank has its own record here. There is a one-to-many relationship with `skills`: there could be more than one skill from a certain bank (eg: account info, payment initiation - both from the same Bank). This table is maintained manually because it's mostly static information. You would add a new Servicer when the skill you want to implement is from a new Bank you don't have already.

`Sessions, steps` tables: keeps a local state for implementing the [Sessions API](https://github.com/finqware/gitbook-public-docs/blob/main/dev-guide/designing-a-tenant-app/broken-reference/README.md). By keeping this state you make sure the client app is 'guided' to show the right screen and you avoid wrongly submitted forms.

### Storing consent data

Following a successful consent flow (finishing with the `temp_token` exchange) your tenant app receives a `credentials_id` and its `access_token`. This pair is used by your app in order to query for data such as: one or more bank accounts, a payment object.

One place to store this information is `user_skills` table which, in this example is a proxy (typical many-to-many proxy table) that makes the connection between the user and the skills/features they chose to connect with.

One thing to note: a consent object (the `credentials_id`/`access_token` pair) may point to more than one resource (eg: bank account). This maps to the PSD2 consent objects which expresses the same relationship. That is why it makes sense to store it in a record that expresses the direct relation between the end-user and skills that they used via the client UX.

### Caching data

Finqware manages its own caching of the data. By default it refreshes the data for you based on a pre-defined schedule. Currently this is four times per day, but it will be possible to be configured via the developer portal.

Our backend is highly available and we serve data with a super-low latency, striving for realtime. However, building and keeping your own cache is something recommended in order to offer a more predictable SLA to your customers.

### Business logic

This is where your own data processing happens: build statistics, apply ML models, transform data in any way etc. May be developed in your language of choice.

Your app will probably have a private API (eg: REST or GraphQL) that is consumed by the front-end (unless your data is rendered server-side).

### Custom extensions

We are currently working with selected customers to build custom extensions on top of the base API: income recognition, statistics etc. If your company is interested in such developments, please contact us.


# The front-end

Things to consider while designing the front-end application

Your front-end application most certainly will have to deal with user sessions and various GUI matters that are out of scope here. From an integration with Finqware standpoint there are few notable things:

* an end-user needs to see a list of Banks to connect to. Your backend has to maintain an inventory of skills that you chose to implement for your tenant app.
* each connector (skill) may have various tricks to be aware of (eg: a certain Bank may need a list of IBANs as an input). At the moment consent flows are not yet 100% the same from one Bank to another. Make sure you check each skill doc section in the [developer portal](https://developers.finqware.com) once you configured your tenant app.
* once the user initiates a consent session with a new Bank, they need to submit data step-by-step by following a wizard-based GUI. At least one step will involve a web redirect to a page served directly by the Bank (for the SCA process). Make sure you know how to handle the redirect back using your client-side tech of choice.

### State management

One of the main challenges in developing any quality front-end is state management. State management in web/mobile apps has become a hot topic, especially since Facebook introduced the [flux](https://facebook.github.io/flux/) pattern back in 2014. It's always a matter of taste and depends greatly on what programming language and framework you're using.

In the example below, the client app (developed with [React](https://reactjs.org)) has a central [Redux](https://redux.js.org) state where we keep parameters related to the GUI (eg: the page `loading` flag) and data served by our app's backend such as:

* the available skills/connectors that will show the user which banks to connect to
* data related to the Sessions API that tracks the steps for a consent flow (eg: the user chooses an account-information skill and needs to go through a wizard-like UX to fill some forms and submit data)
* user data - which skills they already connected to. Also we need account data that has to be rendered on the screen.

![](/files/g11Xg4K4P8m1iKH0f6ZL)

Note: this example app is deployed online at [https://play.finqware.com/](https://play.finqware.com).


# Signing API requests

An extra layer of security on top of API keys

The Finqware API v1 has two base endpoints:

* <https://api.finqware.com/v1> - protected by TLS & API keys
* <https://api.finqware.com/v1s> - extra security: message signing & anti-tampering

In order to use the `v1s` endpoints, an external API consumer is required to sign a short-lived JWT with each API call and include the JWS inside an Authorization header. The signed JWT payload will include a digest (sha256) of the request, for anti-tampering protection.


# RS256 infrastructure

Public/private key management

The Finqware **v1s** endpoint uses an asymmetric (RS256) scheme for signing requests:

* the public/private key issuing is based on [Google Cloud's IAM](https://cloud.google.com/iam) (Identity and Access Management) infrastructure.
* each company registered with Finqware will have a [service account](https://cloud.google.com/iam/docs/service-accounts) (managed by Finqware or self-managed, please see below)
* each GCP service account may have up to 10 public/private key pairs that may be created/destroyed when a private key is compromised or for key rotation.
* the public key is automatically published at a Google hosted JWKS endpoint
* an application will issue & sign a JWT token and send it as an **Authorization** header; the Finqware's API gateway verifies the signature (among other claims - iss, aud & exp) using the JWKS endpoint.

Private keys may be either managed by Finqware (a) or self-managed (b):

* a. created & managed by Finqware, distributed using a secure method (eg: GPG encryption)
* b. created by the application developer using their own Google Cloud project (free of charge); the developer will need to share the coordinates for the public key only (the generated service account's email & the JWKS url).

### Self-managed keys

Self-managing your own key pairs requires an account with Google Cloud Platform. Creating an account and a GCP project is free of charge.

#### How to create a public/private key pair

1. Create a service account under the IAM & Admin, service accounts section. The service account requires the `Service Account Token Creator` role.
2. Create a key pair under the new service account. Once created, the private key file is automatically downloaded to your drive.

Once you download the private key file (json) from GCP, open it and extract the public key's coordinates:

* client\_email
* client\_x509\_cert\_url&#x20;

Send this information to Finqware if you self-manage your keys. This is public information, no need to encrypt the communication. Make sure you do not share the full json file or the data under the `private_key` field.

#### Key rotation & revoking

Key rotation:

* Create a new public/private key pair, share the public key with Finqware.&#x20;
* Finqware will register the new public key with the API Gateway.
* Start using the new private key & disable/delete the previous key

Revoking keys may be done from the GCP GUI by doing either or both of:

* disable or delete the key
* disable the service account


# Computing the digest

Guideline for generating the message digest

The signed **Authorization** header includes, among other claims, a sha256 digest of the HTTP request (note: the Finqware API only uses POST application/json requests similar to a GraphQL API).

#### Steps

1. take the json payload and compress it to a single-line json without any whitespaces
   * make sure you do not remove any useful whitespaces (eg: from a debtor name when submitting a payment)
   * it is recommended to use a standard json library to do that instead of your own regex

     ```python
     #
     # Python example
     #

     http_payload = {
       "client_id": "51e2389....02d51",
       "client_app_key": "MDAxNmxvY2F0aWMz...D9rgv7_DySaiYgo", 
       "skill": "bt_ro_aisp_sbx_#2.0"
     }

     # a compact stringified json without any whitespaces 
     compact_http_payload = json.dumps(http_payload, separators=(',', ':')).encode("utf-8")
     ```
2. compute a Base64 (not URL-safe) encoded SHA-256 hash of the compressed json format

   ```python
   digest = hashlib.sha256(compact_http_payload).digest()
   b64_digest = base64.b64encode(digest).decode("utf-8")
   ```

***Note***:

* make sure your HTTP client sends the request with the json keys in the same order as in the payload used when computing the digest


# Signing HTTP requests

Signing API requests with the private key

The Authorization header is a JWS (signed JWT) that includes few standard claims, plus the digest computed as described above. Below there is a complete example in Python with the relevant comments. Once you compute the JWS, just add it to every request as an Authorization header:

```bash
curl -d '{"key1":"value1", "key2":"value2"}' -H "Authorization: Bearer eyJ0e...cYjeaRcw" https://api.finqware.com/v1s/...
```

For some programming languages, Google provides libraries/wrappers for signing payloads, but this may be achieved in any programming language using standard libraries.

* Java, Python, Go [examples](https://cloud.google.com/endpoints/docs/openapi/service-account-authentication#making_an_authenticated_request)
* .Net [wrapper](https://googleapis.dev/dotnet/Google.Apis.Auth/latest/api/Google.Apis.Auth.OAuth2.ServiceAccountCredential.html)
* complete Python example

```python
import time

import google.auth.crypt
import google.auth.jwt
import hashlib
import json
import base64

def generate_jwt():
    now = int(time.time())

    payload = {
        "client_id": "51e2389....02d51",
        "client_app_key": "MDAxNmxvY2F0aWMz...D9rgv7_DySaiYgo", 
        "skill": "bt_ro_aisp_sbx_#2.0"
        }
    
    # a compact stringified json without any whitespaces
    json_payload = json.dumps(payload, separators=(',', ':')).encode("utf-8")

    digest = hashlib.sha256(json_payload).digest()
    b64_digest = base64.b64encode(digest).decode("utf-8")

    # service account email: this is auto-generated by GCP when creating a service account
    sa_email='service-account1@my-gcp-project.iam.gserviceaccount.com'

    # how long this JWS should be valid for.
    #   - each request will have its own JWS so this value should be small
    expiry_length=3600

    # build the payload for your signed Authorization header
    payload = {
        'iat': now,
        # expires after 'expiry_length' seconds.
        "exp": now + expiry_length,
        # iss (issuer) should match the service account's email address
        'iss': sa_email,
        # aud (audience) is alwasy ('api.finqware.com')
        'aud':  'api.finqware.com',
        # sub and email should match the service account's email address
        'sub': sa_email,
        'email': sa_email,
        # a Base64 encoded sha-256 hash of the request payload as described above
        'digest': b64_digest
    }

    # the signing/private key is inside this json file downloaded when creating
    # a public/private key pair for a service account
    sa_keyfile='my-gcp-private-key.json',

    # sign with your service account keyfile
    signer = google.auth.crypt.RSASigner.from_service_account_file(sa_keyfile)
    jwt = google.auth.jwt.encode(signer, payload)

    return jwt

if __name__ == '__main__':
  jwt = generate_jwt()
  print(jwt)
```


# Sessions

An ordered sequence of steps that can be used to build conversational UIs (eg: product onboarding).

## Create session

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/sessions`

Initializes an on-boarding session for a specified skill.

The **tenant\_user\_id** may be any string that uniquely identifies an end-user using your tenant app (eg: uuid, opaque string, etc).

#### Request Body

| Name                                               | Type   | Description                            |
| -------------------------------------------------- | ------ | -------------------------------------- |
| tenant\_user\_id<mark style="color:red;">\*</mark> | string | A unique identifier for your end-user. |
| client\_id<mark style="color:red;">\*</mark>       | string | An identifier for your tenant app.     |
| client\_app\_key<mark style="color:red;">\*</mark> | string | Authorization key.                     |
| skill<mark style="color:red;">\*</mark>            | string | The skill you're implementing.         |

{% tabs %}
{% tab title="200: OK Session successfully started." %}

```javascript
{
    // The nonce is a temporary key that should be used when submitting data for the next step in this session.
    "nonce": "MDAxNmxvY2F0a...z0sBtsOyVdJ04kK",
    "session_id": "58f92378-...-20a052aca460",
    "status": "SESSION_CREATED"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}

## Submit step for session

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/sessions/:id/steps`

Submits data for a certain session step.

#### Path Parameters

| Name                                 | Type   | Description     |
| ------------------------------------ | ------ | --------------- |
| id<mark style="color:red;">\*</mark> | string | The session id. |

#### Request Body

| Name                                         | Type   | Description                                      |
| -------------------------------------------- | ------ | ------------------------------------------------ |
| client\_id<mark style="color:red;">\*</mark> | string | An identifier for your tenant app.               |
| nonce<mark style="color:red;">\*</mark>      | string | A temp key received from the previous step.      |
| skill<mark style="color:red;">\*</mark>      | string | The skill you're implementing.                   |
| step<mark style="color:red;">\*</mark>       | string | The name of the step you're submitting data for. |
| data<mark style="color:red;">\*</mark>       | object | The payload for this specific step.              |

{% tabs %}
{% tab title="200: OK Step successfully submitted." %}

```javascript
{
    // use the step_id if you require to submit more information to this particular step (eg: a file upload)
    "step_id": "58f92378-...-20a052aca460",
    // Use the newly generated nonce to submit data for the next step within the current session.
    "nonce": "MDAxNmxvY2F0a...z0sBtsOyVdJ04kK",
    "status": "SESSION_IN_PROGRESS",
    "data": {}
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    "message": "Error message"
}
```

{% endtab %}
{% endtabs %}


# Tokens

Token related operations

## Token exchange

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/tokens`

Exchange a temp-token for an access-token.

#### Request Body

| Name                                             | Type   | Description                                 |
| ------------------------------------------------ | ------ | ------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>     | string | An identifier for your tenant app.          |
| client\_secret<mark style="color:red;">\*</mark> | string | A tenant app secret.                        |
| temp\_token<mark style="color:red;">\*</mark>    | string | A temporary token that has to be exchanged. |

{% tabs %}
{% tab title="200: OK A pointer to a newly created consent resource, plus its authorization key." %}

```javascript
{
    // A pointer to a newly created consent resource
    "credentials_id": "242a5690-...-b4ed02bebd7f",
    // An authorization key for this particular consent resource
    "access_token": "MDAxNmxvY...iGc_CorFem9_YCg",
    // time (UTC timestamp) when this consent is automatically expired
    "consent_exp": "2020-11-03T11:22:54Z",
    // time (UTC timestamp) when data pointed by this consent is permanently removed from the cache
    "max_data_retention": "2020-12-03T11:22:54Z"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}


# Accounts

Query for bank accounts.

## GET Accounts

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/accounts/get`

Get account data.

#### Request Body

| Name                                               | Type   | Description                                                      |
| -------------------------------------------------- | ------ | ---------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>       | string | An identifier for your tenant app.                               |
| client\_secret<mark style="color:red;">\*</mark>   | string | A tenant app secret.                                             |
| credentials\_id<mark style="color:red;">\*</mark>  | string | A pointer to a consent record created via an onboarding session. |
| access\_token<mark style="color:red;">\*</mark>    | string | An authorization key for this particular consent record.         |
| tenant\_user\_id<mark style="color:red;">\*</mark> | string | A unique identifier for your end-user.                           |

{% tabs %}
{% tab title="200: OK A list of bank accounts and related info." %}

```javascript
[
    {
        "data": {
            "account_schemes": [
                {
                    "identification": "CZ6355...254079",
                    "scheme_name": "IBAN"
                },
                {
                    "identification": "BRDEROBUXXX",
                    "scheme_name": "BICFI"
                }
            ],
            "balances": [
                {
                    // always a positive decimal number.
                    // for overdraft/negative balances check the credit_debit_indicator.
                    "balance_amount": "123.34",

                    "balance_currency": "RON",

                    // check the balances docs page for all supported types
                    "balance_type": "Expected",

                    "credit_limit_included": false,

                    // credit   -> positive or zero amount
                    // debit    -> negative amount (overdraft)
                    "credit_debit_indicator": "credit"
                }
            ],
            "account_sub_type": "Account sub-type",
            "account_type": "Personal current account",
            "currency": "RON",
            "name": "",
            "nickname": ""
        },
        "id": "f3dc1a92-...-b715a988553d",
        "servicer_id": "e5c11467-...-52a6492054d8",
        "servicer_name": "XYZ Bank",
        "timestamp": "2021-02-01T13:14:52Z"
    }
]
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}


# Balances

Query for bank account balances.

## GET Balances

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/balances/get`

Get balances data related to a certain **credentials\_id**.

#### Request Body

| Name                                               | Type   | Description                                                      |
| -------------------------------------------------- | ------ | ---------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>       | string | An identifier for your tenant app.                               |
| client\_secret<mark style="color:red;">\*</mark>   | string | A tenant app secret.                                             |
| credentials\_id<mark style="color:red;">\*</mark>  | string | A pointer to a consent record created via an onboarding session. |
| access\_token<mark style="color:red;">\*</mark>    | string | An authorization key for this particular consent record.         |
| tenant\_user\_id<mark style="color:red;">\*</mark> | string | A unique identifier for your end-user.                           |
| filter                                             | object | A filter object. Criteria in the table below.                    |

{% tabs %}
{% tab title="200: OK A list of bank account balances and related info." %}

```javascript
[
  {
    "account_id": "69a19df6-../-3bc1bddfd89a",
    "data": {
      // always a positive decimal number.
      // for overdraft/negative balances check the credit_debit_indicator.
      "amount": "210.23",

      // credit   -> positive or zero amount
      // debit    -> negative amount (overdraft)
      "credit_debit_indicator": "credit",

      "credit_limit_included": false,

      "credit_line": null,
      "currency": "RON",

      // `date` returned by the bank for certain balance types (eg: ClosingBooked)
      "native_date": "2018-03-30",
      
      // `date-time` for an intermediate balance (eg: InterimAvailable) 
      // note: potentially null
      "native_timestamp": "2021-10-14T09:00:00Z",
      
      "type": "Expected",
    },
    id: "6aac5b32-...-8f8c5f6c653d",

    // `data-time` when this balance was queried by the Finqware middleware
    timestamp: "2020-01-29T07:31:51.689168",
  },
];
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}

| Filter element | Type   | Info                             |
| -------------- | ------ | -------------------------------- |
| account\_id    | string | finqware id for the bank account |
| type           | string | The balance type                 |
| currency       | string | The balance currency             |

```javascript
// Filter example

"filter": {
  "type": "Expected",
  "currency": "RON"
}
```

Finqware always presents at least one type of balance, normalised under the name of ‘Available’ and may also present a normalised ‘Closing’ type, depending on bank data, with the following meaning:

| Balance type | Description                                                                                                                                                                                                                                                                                                 |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Available    | Available balance calculated by the bank in the course of the account servicer's business day, at the time specified, and subject to further changes during the business day. The interim balance is calculated on the basis of booked credit and debit items during the calculation time/period specified. |
| Closing      | Closing balance of amount of money that is cleared on the date specified. Finqware provides a normalised Closing balance only for the accounts where the bank provides an explicit ClosingCleared/ Booked balance for the day.                                                                              |

A more detailed explanation of what each balance means, taking into account other balance parameters, can be found in the following tabel:

| Balance type | Credit\_limit\_included | Credit\_debit\_indicator | Description                                                                                                                                                                                                                                                                                    |
| ------------ | ----------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Available    | false                   | credit/ positive amount  | account balance representing the amount of money which can be spent                                                                                                                                                                                                                            |
|              |                         | debit/ negative amount   | account balance representing borrowed funds out of the account associated overdraft                                                                                                                                                                                                            |
|              | true                    | credit/ positive amount  | total balance representing the sum between the account balance and the value of the associated overdraft; in correlation with a negative amount for the Available                                                                                                                              |
|              |                         | debit/ negative amount   | NA                                                                                                                                                                                                                                                                                             |
| Closing      | false                   | credit/ positive amount  | account balance representing the accounting balance for the amount of money for the official banking date closing                                                                                                                                                                              |
|              |                         | debit/ negative amount   | account balance representing borrowed funds out of the account associated overdraft, at the moment of the banking day closing                                                                                                                                                                  |
|              | true                    | credit/ positive amount  | total balance representing the sum between the account balance and the value of the associated overdraft; in correlation with a negative amount for the Closing credit\_limit\_included = false, it represents the remaining unused amount of the overdraft, at the closing of the banking day |
|              |                         | debit/ negative amount   | NA                                                                                                                                                                                                                                                                                             |

In addition to the two standardised balance types, Finqware may also present other types of balances retrieved from the bank API:

| Balance type           | Description                                                                                                                                                                                                                                                                                                                                         |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ClosingAvailable       | Closing balance of amount of money that is at the disposal of the account owner on the date specified.                                                                                                                                                                                                                                              |
| ClosingBooked          | Balance of the account at the end of the pre-agreed account reporting period. It is the sum of the opening booked balance at the beginning of the period and all entries booked to the account during the pre-agreed account reporting period.                                                                                                      |
| ClosingCleared         | Closing balance of amount of money that is cleared on the date specified.                                                                                                                                                                                                                                                                           |
| Expected               | Balance, composed of booked entries and pending items known at the time of calculation, which projects the end of day balance if everything is booked on the account and no other entry is posted.                                                                                                                                                  |
| ForwardAvailable       | Forward available balance of money that is at the disposal of the account owner on the date specified.                                                                                                                                                                                                                                              |
| Information            | Balance for informational purposes.                                                                                                                                                                                                                                                                                                                 |
| InterimAvailable       | Available balance calculated in the course of the account servicer's business day, at the time specified, and subject to further changes during the business day. The interim balance is calculated on the basis of booked credit and debit items during the calculation time/period specified.                                                     |
| InterimBooked          | Balance calculated in the course of the account servicer's business day, at the time specified, and subject to further changes during the business day. The interim balance is calculated on the basis of booked credit and debit items during the calculation time/period specified.                                                               |
| InterimCleared         | Cleared balance calculated in the course of the account servicer's business day, at the time specified, and subject to further changes during the business day.                                                                                                                                                                                     |
| OpeningAvailable       | Opening balance of amount of money that is at the disposal of the account owner on the date specified.                                                                                                                                                                                                                                              |
| OpeningBooked          | Book balance of the account at the beginning of the account reporting period. It always equals the closing book balance from the previous report.                                                                                                                                                                                                   |
| OpeningCleared         | Opening balance of amount of money that is cleared on the date specified.                                                                                                                                                                                                                                                                           |
| PreviouslyClosedBooked | Balance of the account at the previously closed account reporting period. The opening booked balance for the new period has to be equal to this balance. Usage: the previously booked closing balance should equal (inclusive date) the booked closing balance of the date it references and equal the actual booked opening balance of the current |


# Transactions

Query for bank account transactions.

## GET Transactions

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/transactions/get`

Get transaction data related to a certain **credentials\_id**.

#### Request Body

| Name                                               | Type   | Description                                                      |
| -------------------------------------------------- | ------ | ---------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>       | string | An identifier for your tenant app.                               |
| client\_secret<mark style="color:red;">\*</mark>   | string | A tenant app secret.                                             |
| credentials\_id<mark style="color:red;">\*</mark>  | string | A pointer to a consent record created via an onboarding session. |
| access\_token<mark style="color:red;">\*</mark>    | string | An authorization key for this particular consent record.         |
| tenant\_user\_id<mark style="color:red;">\*</mark> | string | A unique identifier for your end-user.                           |
| filter                                             | object | A filter object. Criteria in the table below.                    |

{% tabs %}
{% tab title="200: OK A list of bank account transactions and related info." %}

```javascript
[
  {
    "account_id": "91ba3b32-...-6b41bf682aa8",
    "timestamp": "2021-02-01T13:14:52Z",
    "id": "99459ac2-a7b3-11e9-b37d-bfb2bf7bff33",
    "utx_id": "Jd+ErYeFaUOWzU37k9y1+fHz/+4v/YwQ/fq8A4jbSjc=",
    
    "data": {
      "amount": "4.27",
      "balance": "9434.52",
      "booking_date_time": "2019-05-11T07:57:00Z",
      "credit_debit_indicator": "debit",
      "currency": "RON",
      "info": "Currency payment or withdrawal",
      "status": "booked",

      // future use
      "details": null,
      "exchange_rate": null
    }
  }
]
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
{
    "message": "Error message"
}
```

{% endtab %}
{% endtabs %}

| Filter element           | Type          | Info                                |
| ------------------------ | ------------- | ----------------------------------- |
| account\_id              | string        | **finqware id** of the bank account |
| currency                 | string        | eg: RON                             |
| status                   | string        | eg: booked                          |
| credit\_debit\_indicator | string        | debit \| credit                     |
| category                 | string        | eg: shopping                        |
| eq                       | decimal       | amount equal to                     |
| gte                      | decimal       | amount >= than                      |
| gt                       | decimal       | amount > than                       |
| lte                      | decimal       | amount <= than                      |
| lt                       | decimal       | amount < than                       |
| booking\_date\_eq        | utc\_datetime | date equal to                       |
| booking\_date\_gte       | utc\_datetime | date later or equal to              |
| booking\_date\_gt        | utc\_datetime | later than                          |
| booking\_date\_lte       | utc\_datetime | earlier or equal to                 |
| booking\_date\_lt        | utc\_datetime | earlier than                        |
| timestamp\_eq            | utc\_datetime | timestamp equal to                  |
| timestamp\_gte           | utc\_datetime | timestamp later or equal to         |
| timestamp\_gt            | utc\_datetime | timestamp later than                |
| timestamp\_lte           | utc\_datetime | timestamp earlier or equal to       |
| timestamp\_lt            | utc\_datetime | timestamp earlier than              |

The **timestamp** represents the time the transaction was inserted in Finqware's database.

```javascript
// Filter example

"filter": {
  "account_id": "91ba3b32-...-6b41bf682aa8",
  "lt": 4.2700000000000001,
  "booking_date_gt": "2025-05-03T00:00:00Z",
  "timestamp_gte": "2025-05-11T00:00:00Z"
}
```

For each transaction Finqware calculates an unique transaction id (utx\_id) that is the same across consents.\
Make sure you always use this id in order to decide if you need to update or insert a record.\
If you already syncronised and inserted in your DB a certain transaction record and you receive it again, you can update the existing record, not insert it again.


# Payments

The Payments API allows customers to securely make account-to-account payments in Europe from your app or website in real time.

Finqware Payments API *(currently in public beta)* enables third parties to set up secure payments on behalf of customers. It provides a unified way of registering new payments on behalf of customers in all integrated banks and works by letting customers connect to their banks and authorize a payment directly from their accounts. Once authorized by the customer, the payment is submitted for processing.

> Under PSD2, a 'Payment Initiation Service' is an online service which accesses a user's payment account to initiate a payment with the user's consent and authentication, according to PSD2 regulations

Given the extensive research already done by Swift for `ISO20022` standard, the API closely follows the spec as a guideline for architecting the structure of the API. This allows us to integrate different types of payments ranging from Single Domestic Payments to International and Bulk Payments.

> Although initially intended to integrate PSD2 Payment Initiation APIs, future extensions will potentially add more capabilities such as working with custom payment APIs *(e.g.: private corporate APIs).*

## Submit Payment Intent step&#x20;

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/sessions/:id/steps`

\- Once an on-boarding session is started, you can submit data using the `session_id`and the`nonce`received in the previous step. Each session is an iteration of steps.

\- Each skill has a different on-boarding process. This example illustrates a payment intent step. At the end of a successful Session, you will receive a SCA link.

#### Request Body

| Name                                         | Type   | Description                                                           |
| -------------------------------------------- | ------ | --------------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark> | string | A unique id for a tenant app, generated through the developer portal. |
| nonce<mark style="color:red;">\*</mark>      | string | Executing the next step/iteration requires a nonce                    |
| skill<mark style="color:red;">\*</mark>      | string |                                                                       |
| step<mark style="color:red;">\*</mark>       | string | e.g. "payment\_intent"                                                |
| data<mark style="color:red;">\*</mark>       | object | Input data for payment step                                           |

{% tabs %}
{% tab title="200 Successful Strong Customer Authentication (SCA) link" %}

```javascript
{
  "status": "SESSION_IN_PROGRESS",
  "data": {
    "headers": {
      "Content-Type": "application/x-www-form-urlencoded"
    },
    "method": "GET",
    "url": "https://www.testbank.com/v1/payments/sepa-credit-transfers/authorize?client_id=XXXXXXXXXXX&code_challenge=BYihra....ChCM&code_challenge_method=S256&redirect_uri=https%3A%2F%2Fdev-api.finqware.com%2Fv1%2Fredirects%2Faisp&response_type=code&scope=PIS%3Ac26a97f&state=de53cb2e-...-a092503c1737"
  }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}

#### Payment input `data` object

In particular, we are following the conventions set by the `ISO20022` `CustomerCreditTransferInitiationV03` message.

* `psu_redirect_link: string` - An URL the end-user is redirected to after completing the flow, back to the tenant app.
* `psu_id: string (optional)` - End-user identification information *(e.g.: a username used also on the bank's web-banking app).* It is required for specific skills.
* `group_header: object (optional)` - Payment group header; not used in single-payments scenario
  * `message_id: string`
  * `txs_no: number`
* `payment_info: array` - List of elements related to the debit side of the transaction. The information is common to all the credit transfers attached to this Payment Information.
  * `payment_info_id: string (optional)` - Unique identification of the Payment Information part assigned by the Initiating Party. Used in bulk payments scenarios. Not required for single payments.
  * `debtor: object (optional)` - Personal information of the debtor
    * `name: string` - Debtor name
    * `address: string (optional)` - Debtor address
    * `postcode: string (optional)` - Debtor postcode
    * `country: string (optional)` - Debtor ISO3166 Country code
  * `debtor_account: object (optional)` - Debtor account
    * `identification: object` - account identification; the only supported option at the moment is IBAN
      * `iban: string` - IBAN account number;
    * `currency: string` - 3 Letter ISO Currency Code (ISO 4217)
  * `transactions: array` - List of Credit Transfer Transaction Information
    * `amount: object` - amount that needs to be transferred
      * `instructed_amount: object` - Instructed amount; the only supported option at the moment
        * `value: string` - amount that needs to be transferred
        * `currency: string`\_ - \_3 Letter ISO Currency Code (ISO 4217)
    * `creditor: object` - Personal information of the creditor
      * `name: string` - Creditor name
      * `address: string (optional)` - Creditor address
      * `postcode: string (optional)` - Creditor postcode
      * `country: string (optional)` - Creditor ISO3166 Country code
    * `creditor_account: object` - Creditor account
      * `identification: object` - account identification; the only supported option at the moment is IBAN
        * `iban: string` - IBAN account number;
      * `currency: string` - 3 Letter ISO Currency Code (ISO 4217)
    * `payment_identification: object (optional)` - Payment identification; required by specific skills.
      * `end_to_end_id: string` - Unique identification assigned by the payer to identify the transaction. This identification will be returned to the payer and passed on to the beneficiary.
    * `remittance_information: object (optional)` - Payment details. Credit transfer may contain either free text as unstructured remittance information or structured remittance information, but not both at the same time *(with the exception of ERI, which makes it possible to send both at the same time)*. In currency payments, unstructured information can be used as long as the initiating bank doesn’t change a structured message to an unstructured one.
      * `unstructured: string` - Payment unstructured details

#### Example request body

```javascript
{
    "client_id": "{{client_id}}",
    "nonce": "{{nonce}}",
    "skill": "rzb_ro_pisp1_sbx_#2.0",
    "step": "payment_intent",
    "data": {
        "psu_redirect_link": "http://your_redirect_uri",
        "psu_id": "9999999998",
        "payment_info": [
            {
                "payment_info_id": "123123",
                "debtor_account": {
                    "identification": {
                        "iban": "RO36RZBR5381428631716833"
                    },
                    "currency": "RON"
                },
                "transactions": [
                    {
                        "amount": {
                            "instructed_amount": {
                                "value": "1",
                                "currency": "RON"
                            }
                        },
                        "creditor": {
                            "name": "Madonna",
                            "postcode": "00000",
                            "country": "RO",
                            "town": "Bucuresti",
                            "address": "Bulevardul 1 Mai"
                        },
                        "creditor_account": {
                            "currency": "RON",
                            "identification": {
                                "iban": "RO34RZBR4494386347175899"
                            }
                        },
                        "payment_identification": {
                            "end_to_end_id": "1"
                        },
                        "remittance_information": {
                            "unstructured": "test rzb-ing"
                        }
                    }
                ]
            }
        ]
    }
}
```

## Get payment

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/payments/get`

Retrieve a payment details and/or status updates. Every time this endpoint is called, Finqware makes a back-to-back API call to the bank for updates.

#### Request Body

| Name                                              | Type   | Description                          |
| ------------------------------------------------- | ------ | ------------------------------------ |
| client\_id<mark style="color:red;">\*</mark>      | string | An identifier for your client app.   |
| client\_secret<mark style="color:red;">\*</mark>  | string | A tenant app secret                  |
| credentials\_id<mark style="color:red;">\*</mark> | string | A pointer to the payment object      |
| access\_token<mark style="color:red;">\*</mark>   | string | An auth token for the payment object |

{% tabs %}
{% tab title="200: OK Payment object successfully retrieved." %}

```javascript
{
    "id": "e2dbc9cf-d1fd-4d77-9ee7-9864b868dec9",
    "data": {
        "payment_info": [
            {
                "payment_info_id": "123123",
                "debtor_account": {
                    "identification": {
                        "iban": "RO36RZBR5381428631716833"
                    },
                    "currency": "RON"
                },
                "transactions": [
                    {
                        "amount": {
                            "instructed_amount": {
                                "value": "1",
                                "currency": "RON"
                            }
                        },
                        "creditor": {
                            "name": "Madonna",
                            "postcode": "00000",
                            "country": "RO",
                            "town": "Bucuresti",
                            "address": "Bulevardul 1 Mai"
                        },
                        "creditor_account": {
                            "currency": "RON",
                            "identification": {
                                "iban": "RO34RZBR4494386347175899"
                            }
                        },
                        "payment_identification": {
                            "end_to_end_id": "1"
                        },
                        "remittance_information": {
                            "unstructured": "test rzb-ing"
                        }
                    }
                ]
            }
        ]
    },
    "status": "payment_completed"
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}

#### Payment lifecycle

A payment goes through a number of stages reflected by a changing `status`.

| Status                    | Description                                                                                                     |
| ------------------------- | --------------------------------------------------------------------------------------------------------------- |
| new\_payment\_input       | The user started a new session and sent the payment details to Finqware                                         |
| payment\_input\_submitted | Finqware submitted the payment details to the bank                                                              |
| payment\_received         | The bank received the payment details and responded with a payment\_id                                          |
| payment\_authorized       | The user authorized the payment and Finqware received an ACK through a redirect or polling after payment status |
| payment\_in\_process      | The payment is processed by the bank                                                                            |
| payment\_completed        | The payment is settled in both debtor's and creditor's accounts                                                 |
| payment\_failed           | Payment cancelled, rejected or failed                                                                           |


# Consents

Manage user consent records (credentials) created through the Sessions API

## GET Consent

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/consents/get`

This endpoint allows a tenant app to check the status for a consent object.

#### Request Body

| Name                                              | Type   | Description                                                      |
| ------------------------------------------------- | ------ | ---------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>      | string | An identifier for your tenant app.                               |
| client\_secret<mark style="color:red;">\*</mark>  | string | A tenant app secret.                                             |
| credentials\_id<mark style="color:red;">\*</mark> | string | A pointer to a consent record created via an onboarding session. |
| access\_token<mark style="color:red;">\*</mark>   | string | An authorization key for this particular consent record.         |

{% tabs %}
{% tab title="200: OK Consent successfully retrieved." %}

```javascript
{
    // read | delete
    "op_type": "read",
    "code": "credentials_info",
    "http": 200,
    "message": "Consent info retrieved",
    "result": {
        "consent_exp": "2022-05-02T14:21:44Z",
        "credentials_id": "519e...25fd5",
        "originator": {
            "country": "Romania",
            "servicer": "Raiffeisen Bank Romania",
            "skill": "rzb_ro_aisp_sbx_#1.0"
        },
        
        // ACTIVE | DELETED | EXPIRED
        "status": "ACTIVE",
        
        "tenant_app_info": {
            "client_id": "8fbc3f...d4dc58b1",
            "name": "psd2-tests"
        },
        "utc_created": "2020-07-05T21:48:06Z",
        "utc_last_update": "2020-07-05T21:48:27Z",
        "consent_exp": "2020-11-03T11:22:54Z",
        "max_data_retention": "2020-12-03T11:22:54Z"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}

## DELETE Consent

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/consents/delete`

The delete operation updates the state of a given consent from ACTIVE to DELETED.

A DELETED consent pointed by its credentials\_id cannot be used anymore to retrieve account data (accounts, balances, transactions).

This is an idempotent operation.

#### Request Body

| Name                                              | Type    | Description                                                                                 |
| ------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>      | string  | An identifier for your tenant app.                                                          |
| client\_secret<mark style="color:red;">\*</mark>  | string  | A tenant app secret.                                                                        |
| credentials\_id<mark style="color:red;">\*</mark> | string  | A pointer to a consent record created via an onboarding session.                            |
| access\_token<mark style="color:red;">\*</mark>   | string  | An authorization key for this particular consent record.                                    |
| pcd\_data\_retention                              | integer | How long (in minutes) will the cached data be retained in the cache after consent deletion. |

{% tabs %}
{% tab title="200: OK Consent successfully retrieved." %}

```javascript
{
    "code": "credentials_deleted",
    "http": 200,
    "message": "Consent deleted",
    "op_type": "delete",
    "result": {
        "client_id": "27c3605a-65f1-4ef3-8b3c-fa814bde5ff7",
        "credentials_id": "b6e01945-6de1-465a-af9b-c74227bca47a",
        "max_data_retention": "2022-06-01T14:21:44Z"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}


# Catalogs

A programatic method to query the list of skills available for integration.

## GET Skills

<mark style="color:green;">`POST`</mark> `https://api.finqware.com/v1/skills/get`

This endpoint allows you query the list of Finqware skills.

#### Request Body

| Name                                             | Type   | Description                        |
| ------------------------------------------------ | ------ | ---------------------------------- |
| client\_id<mark style="color:red;">\*</mark>     | string | An identifier for your tenant app. |
| client\_secret<mark style="color:red;">\*</mark> | string | A tenant app secret.               |

{% tabs %}
{% tab title="200: OK A list of Finqware skills and related info." %}

```javascript
[
     {
        "country": "Romania",
        
        // sandbox | production - this is related to the external API (skill) type 
        "level": "sandbox",
        
        // the financial institution providing the API
        "service_provider": "XYZ Bank",
        
        // the internal Finqware name/identifier for the skill, including the version
        "skill": "xyz_ro_aisp_sbx_#1.0",
        
        "skill_description": "Account information backed by PSD2 AIS",
        
        // currently account_information | payment_initiation
        "skill_type": "account_information",
        
        // a list of steps required to be implemented by the tenant app
        "steps": [
            {
                "name": "account_input",
                "order": 1,
                "data": {
                    "accounts": [
                        {
                            "currency": "string",
                            "iban": "string"
                        }
                    ],
                    "psu_id": "string"
                }
            },
            {
                "name": "sca",
                "order": 2
                "data": {
                    "psu_redirect_link": "string"
                }
            }
        ],
        "version": "1.0"
    },
    {
        ...
    }
]
```

{% endtab %}

{% tab title="400: Bad Request " %}

```javascript
// check the errors docs page for details
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400,
  "code": "invalid_client_id",
  "message": "error message"
}
```

{% endtab %}
{% endtabs %}


# Errors

A list of standard errors & codes.

## Notes

* The errors returned by the middleware are technical- not meant to be used in a user-facing application.
* Please use these messages for internal logging and map them to user-friendly messages depending on your particular app architecture and use case.
* When reporting an error to Finqware, please include the provided `id`.

## Schema

API errors respect this common structure:

```javascript
{
  "id": String,
  "type": String,
  "http": Integer,
  "code": String,
  "message": String
}
```

Description of fields:

* id: an error id used for debugging
* type: a more generic class of errors
* http: a standard http code (200, 4xx, 5xx)
* code: a more specific error code
* message: developer friendly message and eventual hints

### Invalid requests

Errors generated due to incorrect input.

```javascript
{
  "id": "uuid",
  "type": "invalid_request",
  "http": 400 | 404,
  "code": "missing_fields" | 
          "unknown_fields" |
          "invalid_field" |
          "invalid_credentials_id" |
          "invalid_client_id" |
          "invalid_client_secret" |
          "invalid_access_token" |
          "invalid_input" |
          "invalid_body" |
          "invalid_headers" |
          "not_found" |
          "invalid_step" |
          "invalid_session_id" |
          "invalid_skill_name" |
          "invalid_pcd_data_retention" |
          "tpp_redirect_error" 
  "message": "Detailed error message"
}
```

### Unauthorized

Errors generated due to incorrect input, related to various security tokens.

```javascript
{
  "id": "uuid",
  "type": "unauthorized",
  "http": 401,
  "code": "invalid_api_keys" |
          "unauthorized_tenant" |
          "invalid_access_token" |
          "invalid_credentials_id" |
          "invalid_client_id" |
          "invalid_client_secret" |
          "invalid_client_app_key" |
          "inactive_credentials" |
          "expired_credentials" |
          "invalid_uuid" |
          "invalid_tenant_keys" |
          "invalid_api_keys" |
          "invalid_temp_token"
  "message": "Detailed error message"
}
```

### External API errors

Errors generated by external APIs. Sometimes these errors are returned even when correct input is provided.

```javascript
{
  "id": "uuid",
  "type": "external_api_error",
  "http": 400,
  "code": "external_api_connection_error" |
          "external_api_too_many_requests" |
          "external_api_unauthorized" |
          "external_api_forbidden" |
          "external_api_duplicated_consent" |
          "external_api_expired_consent" |
          "external_api_invalid_psu_id" |
          "external_api_server_error" |
  "message": "Detailed error message"
}
```

### Internal server errors

```javascript
{
  "type": "server_error",
  "http": 500,
  "code": "internal_server_error" |
          "planned_maintenance"
  "message": "Detailed error message"
}
```


