Balances

Understand how Infrarails represents and maintains financial values.

Balances are a central part of the Infrarails accounting model.

Each account maintains financial amounts in integer minor units, allowing applications to work with currency values without relying on floating-point storage.

Balance fields

The core account model includes two balance fields.

FieldDescription
available_balanceAvailable balance in integer minor units
pending_balancePending balance in integer minor units

Both fields must be interpreted using the account's currency and currency exponent.

Minor units

Infrarails stores monetary amounts as integers.

For currencies with an exponent of 2, the stored amount represents hundredths of the currency unit.

For example:

Stored valueEUR amount
1€0.01
100€1.00
1699€16.99
10000€100.00
125050€1,250.50
1000000€10,000.00

Currency exponent

The currency exponent determines the relationship between stored integer values and their human-readable representation.

The general formula is:

Display amount = Stored amount / (10 ^ currency_exponent)

For an exponent of 2:

Stored amount: 1699
Currency exponent: 2

1699 / 100 = 16.99

The result is EUR 16.99 when the account currency is EUR.

Applications should use the exponent provided by the account rather than hardcoding two decimal places for every currency.

Available balance

The available balance represents the account's available financial position according to the ledger's accounting rules.

For example, consider an account with:

{
  "currency": "EUR",
  "currency_exponent": 2,
  "available_balance": 250000
}

Its available balance is EUR 2,500.00.

Pending balance

The pending balance is maintained separately from the available balance.

For example:

{
  "currency": "EUR",
  "currency_exponent": 2,
  "available_balance": 250000,
  "pending_balance": 50000
}

This represents:

  • Available balance: EUR 2,500.00
  • Pending balance: EUR 500.00

These values should not automatically be added together or interpreted as a withdrawable total. Their precise meaning depends on the ledger's transaction posting rules.

Balance changes

Financial movements should be performed through supported ledger transaction operations.

For example, consider two EUR accounts:

AccountInitial available balance
Account A€1,000.00
Account B€250.00

A completed transfer of EUR 100.00 from Account A to Account B would produce:

AccountBeforeAfter
Account A€1,000.00€900.00
Account B€250.00€350.00

This example assumes no additional fees, holds, or other adjustments.

Precision and arithmetic

Avoid floating-point arithmetic for financial values.

For example, the following calculation may introduce precision issues:

const total = 0.1 + 0.2;

Instead, perform monetary calculations using integer minor units:

const amountA = 10;
const amountB = 20;

const totalMinorUnits = amountA + amountB;

// 30 minor units = EUR 0.30

For values exceeding JavaScript's safe integer range, use an appropriate arbitrary-precision representation and follow the API's numeric serialization requirements.

Displaying balances

The following JavaScript helper formats safe integer minor-unit values using an account's currency exponent.

function formatBalance(amount, currency, exponent) {
  if (!Number.isSafeInteger(amount)) {
    throw new Error("Amount must be a safe integer");
  }

  if (!Number.isInteger(exponent) || exponent < 0 || exponent > 20) {
    throw new Error("Invalid currency exponent");
  }

  const negative = amount < 0;
  const absolute = BigInt(amount);
  const magnitude = negative ? -absolute : absolute;
  const divisor = 10n ** BigInt(exponent);

  const whole = magnitude / divisor;
  const fraction = magnitude % divisor;

  const formatted = exponent === 0
    ? whole.toString()
    : `${whole}.${fraction.toString().padStart(exponent, "0")}`;

  return `${negative ? "-" : ""}${formatted} ${currency}`;
}

// Example
formatBalance(1699, "EUR", 2);
// "16.99 EUR"

This helper is illustrative. Applications should also use the currency's appropriate locale formatting rules for user-facing displays.

Balance consistency

Applications should treat the ledger as the authoritative source for account balances.

Avoid maintaining independent financial totals without reconciliation against the ledger.

When displaying cached balances, consider the possibility that new transactions have been processed since the last synchronization.

Best practices

  • Store and transmit monetary values using the API's documented numeric representation.
  • Respect each account's currency exponent.
  • Avoid floating-point financial calculations.
  • Do not update ledger balances directly.
  • Distinguish available and pending balances.
  • Validate account currency compatibility.
  • Reconcile derived financial reports against authoritative ledger records.
  • Use idempotency for eligible financial operations.

Next steps

Continue with Transactions to understand how financial operations affect accounts and balances.


Did this page help you?