# 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.