# Historical balances (/data-api/guides/resources/best-practices/historical-balances)

Estimate historical account balances by working backwards from the current balance through posted transactions.



Fiskil's Banking API returns the current account balance, rather than a historical balance series. You can estimate a running balance by starting with `current_balance` and reversing the posted transactions, newest first.

Use this for balance trends and cash flow views. These are **calculated balances**, not bank-provided historical balances or a substitute for a bank statement.

Retrieve the data [#retrieve-the-data]

1. Fetch the account's [current balance](/data-api/api-reference/getBankingBalances). Use `current_balance`, not `available_balance`, which represents funds available to transfer.
2. Fetch its [transactions](/data-api/api-reference/getBankingTransactionsV2) with `status=POSTED`. Retrieve every page using the response's `links.next` until there are no more pages.
3. Keep the balance and transactions scoped to the same institution, account and currency. If you combine responses, avoid counting the same transaction more than once; `fiskil_id` identifies a transaction record.

```http
GET /v1/banking/balances?end_user_id={end_user_id}&account_id={account_id}
GET /v1/banking/transactions?end_user_id={end_user_id}&account_id={account_id}&status=POSTED
```

The transaction request can include `from` in RFC3339 format, for example `2026-10-01T00:00:00Z`. You need **all posted movements between the historical point and the balance you start from**. Do not stop at an earlier `to` date while using today's balance: that would omit intervening movements. Date filters exclude transactions with neither a posting nor an execution datetime.

Wait for transaction syncing to complete before calculating. Fetching a live balance with `fetch=true` does not also refresh transaction history. Check data freshness and refresh transactions separately when needed; separate API calls do not provide an atomic balance-and-transactions snapshot.

Calculate the running balance [#calculate-the-running-balance]

Sort by `posting_date_time`, newest first. For each transaction:

1. Record the running value as `balance_after`.
2. Subtract the signed `amount` to obtain the balance before that transaction.

Negative amounts are outgoing payments, so subtracting a negative amount adds it back. For example, starting from a current balance of AUD 950:

| Transaction (newest first) | Amount  | Calculated balance after | Calculated balance before |
| -------------------------- | ------- | ------------------------ | ------------------------- |
| Purchase                   | -50.00  | 950.00                   | 1,000.00                  |
| Deposit                    | +200.00 | 1,000.00                 | 800.00                    |

This Python example shows the calculation after you have retrieved and validated the data. Use decimal arithmetic for money rather than floating-point numbers.

```python
from datetime import datetime
from decimal import Decimal

def balance_timeline(current_balance, posted_transactions):
    # One account/currency, all pages, unique records, and POSTED only.
    # Require valid posting timestamps; do not silently skip missing data.
    transactions = sorted(
        posted_transactions,
        key=lambda tx: datetime.fromisoformat(
            tx["posting_date_time"].replace("Z", "+00:00")
        ),
        reverse=True,
    )
    balance = Decimal(current_balance)  # Pass the API's decimal string.
    timeline = []
    for tx in transactions:
        timeline.append({
            "fiskil_id": tx["fiskil_id"],
            "posting_date_time": tx["posting_date_time"],
            "balance_after": str(balance),
        })
        balance -= Decimal(tx["amount"])
    return timeline
```

Accuracy and daily balances [#accuracy-and-daily-balances]

* **Timing and completeness:** Missing transactions, delayed posting, corrections, or different balance and transaction refresh times can shift the calculated history. Fetching all available pages does not guarantee the bank has supplied every movement. Do not present the result as an exact ledger reconciliation.
* **Pending transactions:** Exclude them to avoid counting a payment twice when it posts. If the institution's current balance already reflects pending movements, a posted-only calculation may still differ from its historical ledger.
* **Transaction order:** Equal posting timestamps do not reveal the bank's posting order. Intermediate balances within that group are ambiguous. If a posting timestamp is missing, flag the record; using execution time cannot establish its posting order.
* **Daily views:** Use the balance after the latest posted transaction in each day, grouping in your chosen reporting timezone. Resolve timestamp ties as a group. Carry the last closing balance forward over days without movements, and label the current day as partial. These remain estimates subject to the same completeness and timing limits.
* **Currency:** Never mix currencies. Only calculate a currency-specific timeline when you have a matching starting balance and complete movements in that currency; do not assume a multi-currency purse's available amount is a posted ledger balance.
