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

# Bank Account Transactions

> Retrieve the bank accounts and transactions connected to Bolta, request a sync, and page through changes with a cursor.

## What you can retrieve

Retrieve the bank accounts and transactions connected to your own business in Bolta. The API returns the transactions Bolta fetched from the bank as is, and you can request a sync when you need one. Each API key covers the one business it belongs to.

| Path                                | Purpose                                             |
| ----------------------------------- | --------------------------------------------------- |
| `GET /v1/bankAccounts`              | Connected bank accounts and the sync status of each |
| `GET /v1/bankAccounts/transactions` | Loaded transactions (cursor based)                  |
| `POST /v1/bankAccounts:sync`        | Request a transaction sync                          |

## Requirements

These calls deduct no points. Instead, you need a Standard plan or higher. A free trial also qualifies when the trial plan is Standard or higher.

When your plan does not qualify, all three paths return `402` with `PLAN_UPGRADE_REQUIRED`. Upgrade your plan from the billing menu in the Bolta dashboard, then call again.

<Info>
  Connect bank accounts in the Bolta dashboard first.
</Info>

None of the three paths needs issuer registration, a certificate, or `Bolta-Client-Reference-Id`. Send `Basic {apiKey}` in the `Authorization` header. See the [authentication guide](/en/docs/api-introduction/authentication).

## Key limits

| Item                     | Limit                                                       |
| ------------------------ | ----------------------------------------------------------- |
| Sync request             | Once every 30 minutes and 12 times in 24 hours per business |
| Visibility               | About 5 minutes after the change in Bolta                   |
| Items per call (`limit`) | Up to 500. Defaults to 100                                  |

## Account list

```bash theme={"dark"}
curl https://xapi.bolta.io/v1/bankAccounts \
  -H "Authorization: Basic {apiKey}"
```

```json theme={"dark"}
{
  "items": [
    {
      "id": "1",
      "bankCode": "004",
      "bankName": "국민은행",
      "accountNumber": "123456-01-234567",
      "name": "운영자금",
      "currencyCode": "KRW",
      "lastSyncedAt": "2026-09-18T00:00:12Z",
      "syncStatus": "IDLE"
    }
  ]
}
```

| Field           | Type           | Description                                                       |
| --------------- | -------------- | ----------------------------------------------------------------- |
| `id`            | string         | Account identifier                                                |
| `bankCode`      | string         | Three-digit KFTC bank code. See the bank code table below         |
| `bankName`      | string         | Bank name                                                         |
| `accountNumber` | string         | Account number with hyphens                                       |
| `name`          | string         | Alias set in the dashboard. Falls back to the bank's account name |
| `currencyCode`  | string         | ISO 4217 currency code. `KRW`, `USD`, `JPY`                       |
| `lastSyncedAt`  | string or null | Time of the last completed sync (UTC)                             |
| `syncStatus`    | string         | `IDLE`, `IN_PROGRESS`, `FAILED`                                   |

### Bank codes

`bankCode` is the three-digit standard bank code assigned by the Korea Financial Telecommunications & Clearings Institute (KFTC). Bolta supports connecting accounts at these banks:

| `bankCode` | Bank                                      |
| ---------- | ----------------------------------------- |
| `002`      | Korea Development Bank                    |
| `003`      | IBK Industrial Bank of Korea              |
| `004`      | KB Kookmin Bank                           |
| `007`      | Suhyup Bank                               |
| `011`      | NH NongHyup Bank                          |
| `020`      | Woori Bank                                |
| `023`      | SC First Bank                             |
| `027`      | Citibank Korea                            |
| `031`      | iM Bank (formerly Daegu Bank)             |
| `032`      | Busan Bank                                |
| `034`      | Kwangju Bank                              |
| `035`      | Jeju Bank                                 |
| `037`      | Jeonbuk Bank                              |
| `039`      | Kyongnam Bank                             |
| `045`      | MG Community Credit Cooperatives          |
| `048`      | National Credit Union Federation of Korea |
| `071`      | Korea Post                                |
| `081`      | Hana Bank                                 |
| `088`      | Shinhan Bank                              |
| `089`      | K Bank                                    |

Local NongHyup cooperative accounts also use `011`.

## Transactions

```bash theme={"dark"}
curl "https://xapi.bolta.io/v1/bankAccounts/transactions?limit=100" \
  -H "Authorization: Basic {apiKey}"
```

| Parameter         | Required | Description                                                        |
| ----------------- | -------- | ------------------------------------------------------------------ |
| `from`            | No       | Start of the transaction date range. `YYYY-MM-DD` (KST, inclusive) |
| `to`              | No       | End of the transaction date range. `YYYY-MM-DD` (KST, inclusive)   |
| `bankAccountId`   | No       | Account `id` from the account list                                 |
| `transactionType` | No       | `DEPOSIT`, `WITHDRAW`, `OTHER`                                     |
| `cursor`          | No       | `nextCursor` from the previous response                            |
| `limit`           | No       | 1 to 500. Defaults to 100                                          |

Without a date range, the API returns every loaded transaction.

```json theme={"dark"}
{
  "items": [
    {
      "status": "ACTIVE",
      "id": "1",
      "bankAccountId": "1",
      "bankCode": "004",
      "accountNumber": "123456-01-234567",
      "transactionAt": "2026-09-01T00:30:00Z",
      "transactionType": "DEPOSIT",
      "amount": 1100000,
      "balanceAfterTransaction": 5100000,
      "description": "주식회사볼타",
      "currencyCode": "KRW"
    },
    {
      "status": "REMOVED",
      "id": "6"
    }
  ],
  "nextCursor": "djI6MTc4ODU3MDAwMDAwMDAwMDo2OjJ6OWZiOA",
  "hasMore": false
}
```

The item shape depends on `status`.

| `status`  | Meaning                                                                                           | Fields                         |
| --------- | ------------------------------------------------------------------------------------------------- | ------------------------------ |
| `ACTIVE`  | A transaction visible in the Bolta dashboard                                                      | Every field in the table below |
| `REMOVED` | A transaction hidden from the dashboard, for example by disconnecting the account or archiving it | `status`, `id`                 |

| Field                             | Type           | Description                                                                |
| --------------------------------- | -------------- | -------------------------------------------------------------------------- |
| `items[].status`                  | string         | `ACTIVE`, `REMOVED`                                                        |
| `items[].id`                      | string         | Transaction identifier                                                     |
| `items[].bankAccountId`           | string         | Account `id`                                                               |
| `items[].bankCode`                | string         | Bank code of the account. Same as `bankCode` in the account list           |
| `items[].accountNumber`           | string         | Account number with hyphens                                                |
| `items[].transactionAt`           | string         | Transaction time (UTC)                                                     |
| `items[].transactionType`         | string         | `DEPOSIT`, `WITHDRAW`, `OTHER`                                             |
| `items[].amount`                  | number         | Transaction amount. Zero or greater; `transactionType` gives the direction |
| `items[].balanceAfterTransaction` | number         | Balance after the transaction                                              |
| `items[].description`             | string or null | Bank memo                                                                  |
| `items[].currencyCode`            | string         | Currency code of the account                                               |
| `nextCursor`                      | string         | Cursor to pass on the next call                                            |
| `hasMore`                         | boolean        | Whether more items are available right now                                 |

`OTHER` marks a transaction where the bank reported zero for both the deposit and withdrawal amounts, so `amount` is 0.

## Order and cursor

The API returns transactions in the order they changed in Bolta, not in transaction time order.

To show the newest transactions first, sort by `transactionAt` after you receive them.

The same `id` can arrive more than once. Apply items by `id` in the order you receive them.

* `ACTIVE`: Overwrite the item with the same `id`, or add it if none exists.
* `REMOVED`: Delete the item with the same `id`, or ignore it if none exists.

### Collection steps

1. Call without a cursor, then keep calling with `nextCursor` until `hasMore` is `false`.
2. Save the last `nextCursor`. The API fills `nextCursor` even when `hasMore` is `false`. If you use several sets of filters, save a cursor for each.
3. On your next collection, call with the saved cursor. You receive only the transactions that changed since then.

<Warning>
  `hasMore` can be `true` even when `items` is empty. Decide whether to continue from `hasMore`, not from `items`.
</Warning>

Right after a sync finishes, wait about 5 minutes before you continue.

Send the cursor exactly as received. A cursor is bound to the filters (`from`, `to`, `bankAccountId`, `transactionType`) and the API key it was issued for. After you change the filters or the API key, start over without a cursor. The API rejects an old cursor with `400` and `INVALID_CURSOR`. You can change `limit` on any page.

## Sync request

Bolta fetches transactions periodically. Request a sync only when you need the latest transactions sooner.

```bash theme={"dark"}
curl -X POST https://xapi.bolta.io/v1/bankAccounts:sync \
  -H "Authorization: Basic {apiKey}"
```

```json theme={"dark"}
{
  "acceptedAt": "2026-09-18T03:00:00Z",
  "nextAvailableAt": "2026-09-18T03:30:00Z"
}
```

The API only accepts the request with `202 Accepted`, and the bank lookup runs asynchronously. Check progress with `syncStatus` in the account list. When `IN_PROGRESS` ends, continue fetching transactions with your saved cursor.

See [Key limits](#key-limits) for the request limits. `nextAvailableAt` reflects only the 30-minute interval, not the 24-hour count.

| Status code | Error code                   | Meaning                                                           |
| ----------- | ---------------------------- | ----------------------------------------------------------------- |
| `202`       | -                            | Accepted                                                          |
| `409`       | `SYNC_IN_PROGRESS`           | A sync is already running. Request again after it ends            |
| `422`       | `BANK_ACCOUNT_NOT_CONNECTED` | No bank account is connected                                      |
| `429`       | `SYNC_RATE_LIMITED`          | Request limit exceeded. Wait for the `Retry-After` seconds        |
| `503`       | `SYNC_UNAVAILABLE`           | Temporarily unable to evaluate the request. Request again shortly |

A request rejected because a sync is already running (`409`) does not count toward the limit.

## Testing with a test key

Test keys return fixed samples regardless of your subscription, and sync requests use no quota.

| Account `id` | `bankCode` | Account number     |
| ------------ | ---------- | ------------------ |
| `1`          | `004`      | `123456-01-234567` |
| `2`          | `088`      | `110-123-456789`   |

| Transaction `id` | Account | Transaction time (UTC) | Type       | Amount    | Status    |
| ---------------- | ------- | ---------------------- | ---------- | --------- | --------- |
| `1`              | `1`     | 2026-09-01T00:30:00Z   | `DEPOSIT`  | 1,100,000 | `ACTIVE`  |
| `2`              | `1`     | 2026-09-01T06:10:00Z   | `WITHDRAW` | 55,000    | `ACTIVE`  |
| `3`              | `2`     | 2026-09-02T01:00:00Z   | `DEPOSIT`  | 330,000   | `ACTIVE`  |
| `4`              | `1`     | 2026-09-03T08:45:00Z   | `WITHDRAW` | 2,200,000 | `ACTIVE`  |
| `5`              | `2`     | 2026-09-04T02:20:00Z   | `DEPOSIT`  | 770,000   | `ACTIVE`  |
| `6`              | `2`     | 2026-09-04T03:00:00Z   | `WITHDRAW` | 12,000    | `REMOVED` |

Transaction `6` is archived, so only `status` and `id` come back. Call with `limit=3` to see cursor paging across two pages. Test keys skip the 5-minute delay.

## Errors

| Status code | Error code                   | Condition                                                                                  |
| ----------- | ---------------------------- | ------------------------------------------------------------------------------------------ |
| `400`       | `INVALID_REQUEST`            | Invalid date format, `from` later than `to`, or an invalid `transactionType` or `limit`    |
| `400`       | `INVALID_CURSOR`             | Modified or malformed cursor, or filters or API key differ from when the cursor was issued |
| `401`       | -                            | API key authentication failed. Empty response body                                         |
| `402`       | `PLAN_UPGRADE_REQUIRED`      | Plan below Standard                                                                        |
| `404`       | `BANK_ACCOUNT_NOT_FOUND`     | `bankAccountId` that does not exist or belongs to another business                         |
| `409`       | `SYNC_IN_PROGRESS`           | A sync is already running                                                                  |
| `422`       | `BANK_ACCOUNT_NOT_CONNECTED` | No bank account is connected                                                               |
| `429`       | `SYNC_RATE_LIMITED`          | Sync request limit exceeded. Comes with a `Retry-After` header                             |
| `500`       | `INTERNAL_SERVER_ERROR`      | Internal server error                                                                      |
| `503`       | `SYNC_UNAVAILABLE`           | Temporarily unable to evaluate the sync request                                            |
| `503`       | `SERVICE_UNAVAILABLE`        | Temporary internal API communication error                                                 |

See [Error codes](/en/docs/api-introduction/error-codes) for the full list.

## Related documents

* [List Bank Accounts API](/en/api-reference/bank-account-transactions/list-bank-accounts)
* [List Bank Account Transactions API](/en/api-reference/bank-account-transactions/list-bank-account-transactions)
* [Request Bank Account Sync API](/en/api-reference/bank-account-transactions/request-bank-account-sync)
* [Authentication guide](/en/docs/api-introduction/authentication)
