# Read balances
Source: https://fragment.dev/guides/read-balances
[Documentation index](https://fragment.dev/llms.txt)
Fragment supports querying a Ledger Account for its latest balances, historical balances and balance changes.
[Visual: readBalances. View on the HTML page.](https://fragment.dev/guides/read-balances)
## Latest
Use the `ledgerAccount` query to look up a Ledger Account's balance.
```graphql title="GetBalances query"
query GetBalance(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
balance
}
}
```
```json title="GetBalances variables"
{
"ledgerAccount": {
"path": "assets/banks/user-cash",
"ledger": {
"ik": "quickstart-ledger"
}
}
}
```
## Aggregated
Ledger Accounts have three balances:
- `ownBalance` is the sum of all Ledger Lines posted to the Ledger Account, excluding Ledger Lines in child Ledger Accounts
- `childBalance` is the sum of all Ledger Lines posted to the children of this Ledger Account
- `balance` is the sum of all Ledger Lines posted to this Ledger Account and its children
```graphql title="GetAggregatedBalances query"
query GetAggregatedBalances(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
childBalance
balance
}
}
```
```json title="GetAggregatedBalances variables"
{
"ledgerAccount": {
"path": "liabilities/users"
}
}
```
## Consistent
Balance reads are eventually consistent by default. This means that the balance may not reflect all the Ledger Lines in the account.
To read a strongly consistent balance, a Ledger Account must have its balances updated in a strongly consistent manner. This is set in the Schema on a Ledger Account's `consistencyConfig`:
```json title="Strongly consistent Ledger Accounts" expandable
{
"key": "strongly-consistent-ledger-accounts",
"name": "Strongly consistent Ledger Accounts",
"chartOfAccounts": {
"defaultCurrency": { "code": "USD" },
"accounts": [
{
"key": "liabilities",
"type": "liability",
"children": [
{
"key": "users",
"template": true,
"consistencyConfig": {
"totalBalanceUpdates": "strong"
},
"children": [
{
"key": "available",
"consistencyConfig": {
"totalBalanceUpdates": "strong"
}
},
{
"key": "pending"
},
{
"key": "blocked"
}
]
}
]
}
]
}
}
```
Once a Ledger Account's balance is updated consistently, set the `consistencyMode` on balance queries to determine the consistency of the read you issue.
```graphql title="Strongly consistent balance read"
query GetStronglyConsistentBalance(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
balance(consistencyMode: strong)
}
}
```
`consistencyMode` can be set to:
- `strong` to perform a strongly consistent balance read
- `eventual` to perform an eventually consistent balance read
- `use_account` to use the Schema value of the Ledger Account's `consistencyConfig.totalBalanceUpdates` setting
```json title="Strongly consistent balance read variables"
{
"ledgerAccount": {
"path": "liabilities/users:user-1/available",
"ledger": {
"ik": "quickstart-ledger"
}
}
}
```
See the [Configure consistency](https://fragment.dev/markdown/guides/configure-consistency.md) section to learn more about consistency modes.
## Point in time
To query the balance of a Ledger Account at a particular point in time use the `at` argument:
```graphql title="Balance queries"
query GetHistoricalBalances(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
end_of_year: balance(at: "1969")
end_of_month: balance(at: "1969-07")
end_of_day: balance(at: "1969-07-21")
end_of_hour: balance(at: "1969-07-21T02")
}
}
```
If you don't specify `at`, you'll get the [latest balance](https://fragment.dev/markdown/guides/read-balances.md#latest). `at` is supported for all balances and works granularly to the hour.
## Net change
You can also query the net change on a Ledger Account over a specific reporting period. This can be useful for [generating financial statements](https://fragment.dev/markdown/guides/generate-reports.md).
Similar to balances, there are three types of balance changes:
- `ownBalanceChange`, how much `ownBalance` changed
- `childBalanceChange`, how much `childBalance` changed
- `balanceChange`, how much `balance` changed
Balance change queries require you to specify a [`period`](https://fragment.dev/markdown/api-reference/ledger-types.md#scalars-and-enums-period). This can be a year, quarter, month, day or hour.
```graphql title="Balance change queries"
query GetBalanceChanges(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
ownBalanceChange(period: "1969")
childBalanceChange(period: "1969")
balanceChange(period: "1969")
currentYear: balanceChange(period: "1969")
lastYear: balanceChange(period: "1968")
lastYearQ4: balanceChange(period: "1968-Q4")
lastYearDecember: balanceChange(period: "1968-12")
lastYearChristmas: balanceChange(period: "1968-12-25")
lastYearLastHour: balanceChange(period: "1968-12-31T23")
}
}
```
You can also perform multiple balance queries using aliases.
```json title="Balance change query variables"
{
"ledgerAccount": {
"path": "liabilities/users:user-1/available",
"ledger": {
"ik": "quickstart-ledger"
}
}
}
```
## Over a period
Fragment provides two queries for tracking balances and balance changes over time: `balancesDuring` and `balanceChangesDuring`. You can use them to analyze balance history at different granularities.
- `ownBalancesDuring` and `ownBalanceChangesDuring` for a Ledger Account's own balance
- `childBalancesDuring` and `childBalanceChangesDuring` for a Ledger Account's child balance
- `balancesDuring` and `balanceChangesDuring` for a Ledger Account's total balance
To query a Ledger Account's balances, or balance changes, over a period, you must provide:
- `startTime`, a date string in UTC that specifies the first moment of the period
- `duration`, the length of the time period. Duration can be either positive or negative. When negative, the response will be balances, or balance changes, for `duration` period before (not including) `startTime`
- `granularity`, which specifies the unit for `duration`. Valid values are `hourly`, `daily`, or `monthly`
The granularity must have a finer time resolution than the start time string.
| Start Time | Example Start Time | Valid Granularity |
| :----- | :---------- | :------------- |
| Year | "2021" | monthly, daily, hourly |
| Quarter | "2021-Q1" | monthly, daily, hourly |
| Month | "2021-01" | monthly, daily, hourly |
| Day | "2021-01-01" | daily, hourly |
| Hour | "2021-01-01T00" | hourly |
The maximum absolute value for the duration is granularity dependent. Values outside the ranges defined below will be rejected.
| Granularity | Maximum Duration | Time Period |
| :---------- | :--------------- | :---------- |
| monthly | 240 | 20 years |
| daily | 731 | 2 years including a leap year |
| hourly | 744 | 31 days |
```graphql title="Balance history queries"
query GetBalanceHistory(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
# Get monthly balances for a year
yearlyBalances: balancesDuring(
startTime: "2021"
duration: 12
granularity: monthly
) {
startTime
endTime
granularity
nodes {
at
amount {
currency {
code
}
amount
}
}
}
# Get daily balances for January 2021
monthlyBalances: balancesDuring(
startTime: "2021-01"
duration: 31
granularity: daily
) {
startTime
endTime
granularity
nodes {
at
amount {
currency {
code
}
amount
}
}
}
# Get daily balances changes for the two weeks
# before the start of Q4 of 2021
quarterlyChanges: balanceChangesDuring(
startTime: "2021-Q4"
duration: -14
granularity: daily
) {
startTime
endTime
granularity
nodes {
period
amount {
currency {
code
}
amount
}
}
}
# Get hourly balanceChanges for the 48 hour
# period starting on August 9th, 2024 at
# 11:00am UTC
hourlyChanges: balanceChangesDuring(
startTime: "2024-08-09T11"
duration: 48
granularity: hourly
) {
startTime
endTime
granularity
nodes {
period
amount {
currency {
code
}
amount
}
}
}
}
}
```
The format of the response is:
- `startTime`: The start of the period being queried as an ISO Time string
- `endTime`: The last time in the period being queried as an ISO Time string
- `granularity`: The granularity of the data (monthly, daily, or hourly)
- `nodes`: an array of either [HistoricalBalance](https://fragment.dev/markdown/api-reference/ledger-types.md#scalars-and-enums-historicalbalance) or [BalanceChangeDuring](https://fragment.dev/markdown/api-reference/ledger-types.md#scalars-and-enums-balancechangeduring) objects
For multi-currency Ledger Accounts, you must specify the currency you want to query:
```graphql title="Multi-currency balance history"
query GetMultiCurrencyBalanceHistory(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
usdBalances: balancesDuring(
startTime: "2021"
duration: 12
granularity: monthly
currency: { code: USD }
) {
nodes {
at
amount {
amount
}
}
}
gbpChanges: balanceChangesDuring(
startTime: "2021"
duration: 100
granularity: daily
currency: { code: GBP }
) {
nodes {
period
amount {
amount
}
}
}
}
}
```
## Multi-currency mode
For Ledger Accounts using `currencyMode: multi`, you can either:
1. Use the `currency` argument to query the balance in a specific currency
2. Use plural field names (e.g. `balances`) to query all currency balances
```graphql title="Multi-currency balance queries"
query GetMultiCurrencyBalances(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
# Query specific currency
latestUSDBalance: balance(currency: { code: USD })
latestGBPBalance: balance(currency: { code: GBP })
# Query all currencies
balances {
nodes {
currency {
code
}
amount
}
}
}
}
```
```json title="Multi-currency balance query variables"
{
"ledgerAccount": {
"path": "liabilities/users:user-1/available",
"ledger": {
"ik": "quickstart-ledger"
}
}
}
```
See [Handle currencies](https://fragment.dev/markdown/guides/handle-currencies.md#read-balances) for a full list of multi-currency balance queries.
## Timezone offsets
Balance queries respect the Ledger's `balanceUTCOffset` when specifying periods and times. This field is specified when creating the Ledger using the `createLedger` mutation:
```graphql title="createLedger mutation" expandable
mutation CreateLedger(
$ik: SafeString!
$ledger: CreateLedgerInput!
$schema: SchemaMatchInput
) {
createLedger(
ik: $ik,
ledger: $ledger,
schema: $schema
) {
... on CreateLedgerResult {
ledger {
ik
name
created
balanceUTCOffset
schema {
key
}
}
}
... on Error {
code
message
}
}
}
```
```json title="createLedger variables with timezone offset"
{
"ik": "quickstart-ledger",
"ledger": {
"name": "Quickstart Ledger",
"balanceUTCOffset": "-08:00"
},
"schema": {
"key": "quickstart-schema"
}
}
```
The `balanceUTCOffset` is specified as a `UTCOffset` string in the format "±HH:00". All hour-aligned offsets from -11:00 to +12:00 are supported. For example:
- `"-08:00"` for Pacific Time (UTC-8)
- `"-05:00"` for Eastern Time (UTC-5)
- `"+00:00"` for UTC
- `"+01:00"` for Central European Time (UTC+1)
If not specified, the Ledger will use UTC (offset of "+00:00") for balance calculations.
When querying balances, the offset affects how periods and times are interpreted:
- If a Ledger has an offset of `-08:00`, then querying `balance(at: "1969-01-31")` returns the balance at midnight PT on that date, or 8am on 1969-02-01 UTC.
- Querying `balanceChange(period: "1969")` returns the net change between 8am on 1969-01-01 UTC and 8am on 1970-01-01 UTC. This gives you the net change between midnights local time.
- Daylight savings is ignored, so every day throughout the year has exactly 24 hours.