> ## Documentation Index
> Fetch the complete documentation index at: https://docs.finsei.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How can I top up a wallet via Open Banking?

> Learn how to top up a Finsei wallet from a bank account using Open Banking.

Open Banking allows a customer to add money to a Finsei wallet directly from
their bank account.

## Before you start

You need:

* an active Open Banking feature;
* a UUID identifying the payer;
* an optional webhook subscription or WebSocket connection for receiving status updates.

Use [`GET /v3/wallet`](/api-reference/endpoint/get-v3-wallet) or
[`GET /v3/wallet/{id}`](/api-reference/endpoint/get-v3-wallet-id) and check the
following wallet permission:

```json theme={null}
{
  "permissions": {
    "canDepositFromOpenBanking": true
  }
}
```

> [!WARNING]
>
> Do not start an Open Banking deposit when
> `permissions.canDepositFromOpenBanking` is `false`.

Open Banking deposits are currently available only for eligible EUR wallets.

## Open Banking flow

### 1. Get the list of available countries

Call
[`GET /v1/wallet/{id}/deposit/bank/list/country`](/api-reference/endpoint/get-v1-wallet-id-deposit-bank-list-country)
to retrieve the supported countries.

Example response:

```json theme={null}
[
  {
    "id": "DE",
    "label": "Germany"
  },
  {
    "id": "LT",
    "label": "Lithuania"
  }
]
```

Pass the selected country code as `countryId`.

### 2. Calculate the deposit fee

Call
[`POST /v1/wallet/{id}/deposit/bank/fee`](/api-reference/endpoint/post-v1-wallet-id-deposit-bank-fee)
to validate the deposit and calculate its fee without creating a deposit
operation.

Example request:

```json theme={null}
{
  "payerId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 100.01,
  "countryId": "LT"
}
```

Example response:

```json theme={null}
{
  "fee": 1.5,
  "total": 98.51,
  "currencyId": "EUR"
}
```

The response fields have the following meanings:

| Field | Description |
| - | - |
| `fee` | Open Banking deposit fee |
| `total` | Amount credited to the wallet after the fee |
| `currencyId` | Wallet currency |

> [!NOTE]
>
> The calculated fee is a quote. The final fee is fixed when the deposit
> operation is created.

### 3. Start the deposit

Call
[`POST /v1/wallet/{id}/deposit/bank`](/api-reference/endpoint/post-v1-wallet-id-deposit-bank)
to create the deposit operation and obtain the bank authorisation URL.

We recommend providing your own unique `id`. This allows you to correlate
the request with webhook or WebSocket events even if the Open Banking
operation cannot be started.

Example request:

```json theme={null}
{
  "id": "019a1234-5678-7123-8123-123456789abc",
  "payerId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 100.01,
  "countryId": "LT",
  "successUrl": "https://merchant.example.com/open-banking/success",
  "cancelUrl": "https://merchant.example.com/open-banking/cancel",
  "expiryUrl": "https://merchant.example.com/open-banking/expired"
}
```

Successful response:

```json theme={null}
{
  "id": "019a1234-5678-7123-8123-123456789abc",
  "redirectUrl": "https://bank.example.com/payment"
}
```

The successful response status is `200 OK`.

| Field | Description |
| - | - |
| `id` | Open Banking deposit operation UUID |
| `redirectUrl` | Hosted bank page where the customer must confirm the payment |

### 4. Redirect the customer

Open the returned `redirectUrl` in the customer's browser.

The customer will:

1. select their bank;
2. authenticate with the bank;
3. review the payment details;
4. authorise the payment.

After completing the bank flow, the customer is redirected to one of the
URLs provided in the deposit request:

| Request field | When it is used |
| - | - |
| `successUrl` | The bank authorisation flow finished without a redirect error |
| `cancelUrl` | The customer cancelled the authorisation |
| `expiryUrl` | The bank consent expired |

If a URL is not comitted, the default Finsei return URL is used.

> [!WARNING]
>
> A redirect to `successUrl` confirms only that the authorisation flow
> finished without a redirect error. It does not confirm that the wallet
> has been credited.

### 5. Track the deposit status

Use Finsei webhooks or WebSocket events to track the deposit after the
customer has been redirected to their bank.

The operation can have the following statuses:

| Status | Description |
| - | - |
| `PENDING_USER_ACTION` | The hosted bank page has been created and the customer must authorise the payment |
| `PENDING_CREDIT` | The provider reported that the payment was completed, but the incoming bank transfer has not yet been credited |
| `SETTLED` | The incoming payment was received and the Finsei wallet was credited |
| `FAILED` | The hosted payment could not be created or the payment was reported as failed |
| `EXPIRED` | The bank authorisation expired |

Use `SETTLED` as the confirmation that the wallet has been credited.

## Webhook notifications

To receive server-to-server Open Banking status notifications, subscribe to the
following events:

* `v1.openBankingIntent.create`
* `v1.openBankingIntent.update`

Configure the webhook using
[`PATCH /v2/webhook`](/api-reference/endpoint/patch-v2-webhook).

The list of events available for subscription can be obtained using
[`GET /v2/webhook/event`](/api-reference/endpoint/get-v2-webhook-event).

### `v1.openBankingIntent.create`

This event is sent when the hosted bank page is ready and the operation changes
to `PENDING_USER_ACTION`.

Example payload:

```json theme={null}
{
  "id": "019a1234-5678-7123-8123-123456789abc",
  "walletId": "550e8400-e29b-41d4-a716-446655440001",
  "status": "PENDING_USER_ACTION",
  "amount": 100,
  "currencyId": "EUR",
  "redirectUrl": "https://bank.example.com/payment"
}
```

### `v1.openBankingIntent.update`

This event is sent when the deposit operation status changes.

Example payload:

```json theme={null}
{
  "id": "019a1234-5678-7123-8123-123456789abc",
  "walletId": "550e8400-e29b-41d4-a716-446655440001",
  "status": "PENDING_CREDIT",
  "amount": 100,
  "currencyId": "EUR"
}
```

The event can contain one of the following statuses:

* `PENDING_CREDIT`
* `SETTLED`
* `EXPIRED`
* `FAILED`

The `FAILED` event is also sent when
[`POST /v1/wallet/{id}/deposit/bank`](/api-reference/endpoint/post-v1-wallet-id-deposit-bank)
cannot start the deposit and returns:

```json theme={null}
{
  "status": "ERROR",
  "errors": {
    "wallet": "Unable to start deposit, please try again later"
  }
}
```

> [!NOTE]
>
> If you provide `id` in the deposit request, the same value is returned in
> webhook and WebSocket events. This makes failed requests easier to correlate.

## Late incoming payments

The actual incoming bank transfer is the source of truth for wallet crediting.

A bank transfer can arrive after an earlier `FAILED` or `EXPIRED` status. When
Finsei receives a matching incoming payment:

1. the incoming credit payment is created;
2. the wallet is credited;
3. the Open Banking operation changes to `SETTLED`;
4. an updated webhook and WebSocket event are sent.

Your integration must accept a later `SETTLED` event even if it previously
received `FAILED` or `EXPIRED`.

## Request validation

The deposit amount:

* is required;
* must have no more than two decimal places;
* must be within the configured deposit limits.

`payerId` must be a valid UUID.

`countryId` must be a supported ISO 3166-1 alpha-2 country code.

Redirect URLs must use the `http` or `https` scheme.

To validate a request without creating a deposit operation, call:

[`POST /v1/wallet/{id}/deposit/bank?validate=1`](/api-reference/endpoint/post-v1-wallet-id-deposit-bank)

Successful validation response:

```json theme={null}
{
  "status": "VALIDATE",
  "errors": []
}
```

Example response with validation errors:

```json theme={null}
{
  "status": "VALIDATE",
  "errors": {
    "countryId": "Country XX is not available"
  }
}
```

## Possible errors

| HTTP status | Description |
| - | - |
| `401` | The access token is missing or invalid |
| `403` | Open Banking deposits are temporarily unavailable |
| `404` | The wallet was not found, is inactive or is not accessible to the current user |
| `422` | The request is invalid or the hosted payment could not be created |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.