Read balances

FRAGMENT supports querying a Ledger Account for its latest balances, historical balances and balance changes.

Latest

Use the ledgerAccount query to look up a Ledger Account's balance.

GetBalances query
query GetBalance(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    balance
  }
}
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
GetAggregatedBalances query
query GetAggregatedBalances(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    childBalance
    balance
  }
}
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:

Strongly consistent Ledger Accounts"
{
  "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.

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
Strongly consistent balance read variables
{
  "ledgerAccount": {
    "path": "liabilities/users:user-1/available",
    "ledger": {
      "ik": "quickstart-ledger"
    }
  }
}

See the Configure consistency 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:

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

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. This can be a year, quarter, month, day or hour.

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.

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 TimeExample Start TimeValid 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.

GranularityMaximum DurationTime Period
monthly24020 years
daily7312 years including a leap year
hourly74431 days
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 or BalanceChangeDuring objects

For multi-currency Ledger Accounts, you must specify the currency you want to query:

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
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
      }
    }

  }
}
Multi-currency balance query variables
{
  "ledgerAccount": {
    "path": "liabilities/users:user-1/available",
    "ledger": {
      "ik": "quickstart-ledger"
    }
  }
}

See Handle currencies 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:

createLedger mutation"
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
    }
  }
}
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.