# Get the history of a balance

> List the money movements recorded against one balance: top-ups, booking debits and refunds, newest first.

Endpoint: `GET /balances/{balance_id}/history`

Source: https://fx-port.com/docs/api/get-balance-history

`GET /api/v1/balances/{balance_id}/history`

Requires an API key with **Read** permission; a **Read+Write** key works too.

Each entry has a `source`. `transactions` are the authoritative balance movements: sum only these for reconciliation. `flight_balance_operations` and `hotel_balance_operations` are audit records of one booking (initial debit, exchange fee, adjustment, refund); a single action produces both a transaction and an operation. eSIM orders and topups have no audit source: their debits are transactions.

`type` filters on the `type` of the entry and is exact and case sensitive: `DEBIT` matches transactions (upper case) and `debit` matches operations (lower case). Paging is built from the newest 500 entries of each source, so older entries are not reachable: `pagination.total` counts the matching entries, but follow `has_more` to know whether another page can be served.

In the sandbox the answer is always empty. On live a `balance_id` that is not a balance of your agency answers `balance_not_found`.

## Request

### Path parameters

- `balance_id` (string (uuid), required): The `id` of a balance returned by `GET /balances`.

### Query parameters

- `date_from` (string, optional): Inclusive start. Any ISO 8601 spelling is read: a date (`2026-07-01` or `20260701`, taken as 00:00:00 UTC) or a datetime (`2026-07-01T10:30:00Z`) with 1 to 9 fraction digits and an offset written `Z`, `+01:00` or `+0100`. A datetime without an offset is read as UTC. Years 1900 to 2200. In a URL write a `+` as `%2B`. At most 40 characters.
- `date_to` (string, optional): Inclusive end, in the same spellings as `date_from`. A bare date means the end of that day (23:59:59.999999 UTC). It must not be before `date_from`. At most 40 characters.
- `from` (string, deprecated, optional): Legacy name: use `date_from`. Previous name of `date_from`. It still works, with the same spellings, and the response carries a `deprecated_field` warning. At most 40 characters.
- `from_date` (string, deprecated, optional): Legacy name: use `date_from`. Previous name of `date_from`. It still works, with the same spellings, and the response carries a `deprecated_field` warning. At most 40 characters.
- `to` (string, deprecated, optional): Legacy name: use `date_to`. Previous name of `date_to`. It still works, with the same spellings, and the response carries a `deprecated_field` warning. At most 40 characters.
- `to_date` (string, deprecated, optional): Legacy name: use `date_to`. Previous name of `date_to`. It still works, with the same spellings, and the response carries a `deprecated_field` warning. At most 40 characters.
- `type` (string, optional): Keep only entries of this type. Exact and case sensitive: `CREDIT`, `DEBIT` or `REFUND` for transactions; `credit`, `debit` or `refund` for operations. At most 32 characters.
- `page` (integer, optional): The page, starting at 1 (at most 10000). An empty value means not sent. Between 1 and 10000. Default `1`.
- `limit` (integer, optional): Entries per page, from 1 to 100. An empty value means not sent. Between 1 and 100. Default `20`.

### Example request

```bash
curl 'https://api.fx-port.com/api/v1/balances/db002f7a-c136-4f32-b19d-38a2542f2af9/history?limit=5' \
  -H "Authorization: Bearer fxp_test_YOUR_KEY"
```

## Response

### 200: A page of movements.

- `success` (boolean): `true` when the history was returned.
- `data` (array of object): The movements of this page, newest first. Always empty in the sandbox.
  - `source` (string): Where the entry comes from. `transactions` are the authoritative balance movements; the two `*_balance_operations` sources are audit records per booking. One of `transactions`, `flight_balance_operations`, `hotel_balance_operations`.
  - `id` (string (uuid)): Id of the entry.
  - `type` (string): The kind of movement. `transactions` use upper case, `*_balance_operations` lower case. One of `CREDIT`, `DEBIT`, `REFUND`, `credit`, `debit`, `refund`.
  - `amount` (number): The amount, always positive: `type` tells the direction.
  - `currency` (string): The currency of the balance.
  - `description` (string, nullable): A label of the movement, usually with the booking reference.
  - `balanceId` (string (uuid), deprecated): Legacy name: use `balance_id`. `transactions` only. The balance the movement was recorded against. The older name of `balance_id`: same value, use `balance_id`.
  - `balance_id` (string (uuid)): `transactions` only. The balance the movement was recorded against. The snake_case twin of `balanceId`, with the same value: use this name.
  - `bookingRecordId` (string (uuid), deprecated): Legacy name: use `booking_record_id`. `*_balance_operations` only. The internal id of the booking, to match it with the account history. The older name of `booking_record_id`: same value, use `booking_record_id`.
  - `booking_record_id` (string (uuid)): `*_balance_operations` only. The internal id of the booking, to match it with the account history. The snake_case twin of `bookingRecordId`, with the same value: use this name.
  - `createdAt` (string, deprecated): Legacy name: use `created_at`. When the movement was recorded: ISO 8601, UTC. The older name of `created_at`: same value, use `created_at`.
  - `created_at` (string): When the movement was recorded: ISO 8601, UTC. The snake_case twin of `createdAt`, with the same value: use this name.
- `pagination` (object): Where this page sits in the list.
  - `page` (integer): The page returned.
  - `limit` (integer): The page size used.
  - `total` (integer): Number of matching entries. Only the newest ones can be paged to (see the endpoint): follow `has_more`, not `total`.
  - `total_pages` (integer): Number of pages: `total` divided by `limit`, rounded up. Absent when the count is not available.
  - `hasMore` (boolean, deprecated): Legacy name: use `has_more`. `true` when another page can be served. The older name of `has_more`: same value, use `has_more`.
  - `has_more` (boolean): `true` when another page can be served. The snake_case twin of `hasMore`, with the same value: use this name.
- `meta` (object): Facts about the answer.
  - `agencyId` (string (uuid), deprecated): Legacy name: use `agency_id`. The id of your agency, resolved from the key. The older name of `agency_id`: same value, use `agency_id`.
  - `agency_id` (string (uuid)): The id of your agency, resolved from the key. The snake_case twin of `agencyId`, with the same value: use this name.
  - `environment` (string): The environment of the key that made the call: `sandbox` for fxp_test_ keys, `live` for fxp_live_ keys. Present in every JSON body. One of `sandbox`, `live`.
  - `balanceId` (string (uuid), deprecated): Legacy name: use `balance_id`. Live only. The balance of the history. The older name of `balance_id`: same value, use `balance_id`.
  - `balance_id` (string (uuid)): Live only. The balance of the history. The snake_case twin of `balanceId`, with the same value: use this name.
  - `balanceCurrency` (string, deprecated): Legacy name: use `balance_currency`. Live only. The currency of the balance. The older name of `balance_currency`: same value, use `balance_currency`.
  - `balance_currency` (string): Live only. The currency of the balance. The snake_case twin of `balanceCurrency`, with the same value: use this name.
  - `financialOperationsEnabled` (boolean, deprecated): Legacy name: use `financial_operations_enabled`. Sandbox only, always `false`. The older name of `financial_operations_enabled`: same value, use `financial_operations_enabled`.
  - `financial_operations_enabled` (boolean): Sandbox only, always `false`. The snake_case twin of `financialOperationsEnabled`, with the same value: use this name.
  - `message` (string): Sandbox only: why `data` is empty.

```json
{
  "environment": "sandbox",
  "success": true,
  "data": [],
  "pagination": {
    "page": 1,
    "limit": 5,
    "total": 0,
    "total_pages": 0,
    "hasMore": false,
    "has_more": false
  },
  "meta": {
    "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
    "agency_id": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
    "environment": "sandbox",
    "financialOperationsEnabled": false,
    "financial_operations_enabled": false,
    "message": "Sandbox bookings skip debits, refunds, transactions, payouts, and balance operations."
  }
}
```

## Errors

| Status | Code | Example message |
| --- | --- | --- |
| 400 | `invalid_date` | Date parameters must be ISO-8601 values, for example 2026-05-08 or 2026-05-08T10:30:00Z. |
| 400 | `invalid_date_range` | date_from must not be after date_to. |
| 400 | `agency_id_not_allowed` | External API keys resolve agency_id automatically; do not send agency_id as a query parameter. |
| 404 | `balance_not_found` | No balance found for ID 'db002f7a-c136-4f32-b19d-38a2542f2af9'. |
| 422 | `validation_error` | Input should be less than or equal to 100 |
| 503 | `service_overloaded` | The service is temporarily overloaded; retry after the time given in the Retry-After header. |

See [Errors](https://fx-port.com/docs/errors.md) for every code and how to react.

## Related guides

- [Balance history](https://fx-port.com/docs/account/balance-history.md)
