Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt

Use this file to discover all available pages before exploring further.

AccountBalance represents a time-bounded balance snapshot for a bank account, recording opening and closing booked/value figures in a specified currency alongside the valid-from/to period window. It is produced by the financial data ingestion pipeline (connector syncs) and acts as the join anchor for all Transactions, which reference the balance period they were captured within via a foreign key. Each AccountBalance belongs to exactly one Account (and transitively to one Workspace), and includes a suite of verification fields that the reconciliation pipeline populates to flag discrepancies between the bank-reported closing figure and the computed sum of transactions.
NamingValue
ObjectAccount Balance
Resource type (JSON:API type)account_balance
Collection / records rootaccount_balances
REST base/v1/balances
Entity classAccountBalance

API operations

OperationMethod & pathStatus
ListGET /v1/balances✅ Implemented
RetrieveGET /v1/balances/{id}✅ Implemented
CreatePOST /v1/balances🟡 Planned
UpdatePATCH /v1/balances/{id}🟡 Planned
DeleteDELETE /v1/balances/{id}🟡 Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
account_balance_idstring, UUID✅ Yesunique; defaultRaw: gen_random_uuid()Public stable identifier for this balance snapshot. Used in all API responses and external references. Never expose the internal pk.
accounting_balanceobject (JSONB), nullable⚪ NoJSONB; all sub-fields documented belowBank-reported balance figures for this period. Contains four monetary fields (opening_booked, opening_value, closing_booked, closing_value) and the ISO-4217 currency code. closing_booked and closing_value may be null for open (current) periods.
accounting_balance.opening_bookednumber⚪ NoJSONB sub-field; display_type: amountBooked (settled) opening balance for the period in the account’s currency.
accounting_balance.opening_valuenumber⚪ NoJSONB sub-field; display_type: amountValue (including pending) opening balance for the period.
accounting_balance.closing_bookednumber | null⚪ NoJSONB sub-field; display_type: amount; null for open periodsBooked closing balance at the end of the period. Null when balance_at_to is null (current open period).
accounting_balance.closing_valuenumber | null⚪ NoJSONB sub-field; display_type: amount; null for open periodsValue closing balance at the end of the period. Null when balance_at_to is null.
accounting_balance.currencystring⚪ NoJSONB sub-field; display_type: unique_key; ISO-4217 3-letter codeISO-4217 currency code for all monetary figures within this accounting_balance object.
foreign_exchangearray of objects (JSONB), nullable⚪ NoJSONB array; each element has currency_rate, currency_pair, currency_rate_source, currency_rate_atOptional array of FX rate snapshots applied to this balance period. Carries the rate, the pair (e.g. EUR/USD), the source (e.g. ECB), and the timestamp of the rate. Populated by connectors that provide multi-currency balance data.
foreign_exchange[].currency_ratenumber⚪ NoJSONB sub-fieldThe exchange rate value for the currency pair at currency_rate_at.
foreign_exchange[].currency_pairstring⚪ NoJSONB sub-fieldCurrency pair in ISO-4217 slash notation (e.g. EUR/USD).
foreign_exchange[].currency_rate_sourcestring⚪ NoJSONB sub-fieldSource of the exchange rate (e.g. ECB, Plaid, provider-specific).
foreign_exchange[].currency_rate_atstring (ISO-8601 timestamp)⚪ NoJSONB sub-fieldTimestamp at which the FX rate was observed or fixed.
balance_at_fromstring (timestamp), nullable⚪ NocolumnType: timestamp; display_type: datetime; indexed in idx_account_balances_date_range; also in partial index idx_account_balances_currentStart of the validity window for this balance snapshot. Inclusive lower bound of the period. Combined with balance_at_to it defines the interval. Indexed for efficient period range lookups.
balance_at_tostring (timestamp), nullable⚪ NocolumnType: timestamp; display_type: datetime; indexed in idx_account_balances_date_range; null when period is still open (current balance)End of the validity window. Null for the current (open) balance period. The partial index idx_account_balances_current targets rows WHERE balance_at_to IS NULL for fast current-balance lookups.
verified_atstring (timestamp), nullable⚪ NocolumnType: timestampTimestamp when the reconciliation pipeline last successfully verified this balance period (i.e. sum of transactions matched the closing_booked figure within tolerance).
verification_errorboolean, nullable⚪ Nonullable booleantrue | false | nullFlag set by the reconciliation pipeline. True when calculated_balance_diff does not equal expected_balance_diff. Null means verification has not yet run for this period.
verification_error_detailstring (text), nullable⚪ Notype: textHuman-readable explanation of the verification failure. Populated only when verification_error is true. Contains the discrepancy detail reported by the reconciliation pipeline.
calculated_balance_diffnumber (numeric), nullable⚪ Notype: numeric(10,0) — integer precision, no decimal placesThe balance difference computed by the verification pipeline: sum of transaction amounts in the period minus the expected delta between opening and closing booked balances.
expected_balance_diffnumber (numeric), nullable⚪ Notype: numeric(10,0) — integer precision, no decimal placesThe expected balance difference derived from accounting_balance (closing_booked minus opening_booked). Compared against calculated_balance_diff to detect missing or duplicate transactions.
verification_last_run_atstring (timestamp), nullable⚪ NocolumnType: timestampTimestamp of the most recent reconciliation pipeline run against this balance period, regardless of outcome. Distinct from verified_at, which is only stamped on success.
raw_dataunknown (JSONB), nullable⚪ NoJSONB; shape is connector-specificComplete provider-native payload from which this balance was derived (e.g. the full Plaid account/balance JSON response). Shape varies by connector. Preserved for audit and re-processing; not exposed in standard API responses.
created_atstring (timestamptz), 🔒 system✅ YesonCreate: () => new Date(); not nullTimestamp when the record was first persisted. Set automatically by the MikroORM onCreate lifecycle hook.
updated_atstring (timestamptz), 🔒 system⚪ NoonCreate and onUpdate: () => new Date()Timestamp of the last update. Set automatically on create and every subsequent write by the MikroORM onUpdate lifecycle hook.
deleted_atstring (timestamptz), nullable⚪ Nonullable; soft-delete sentinel; partial index idx_account_balances_current WHERE deleted_at IS NULLSoft-delete timestamp. Null means the record is active. All queries must filter deleted_at IS NULL. Also guards the partial index idx_account_balances_workspace_deleted.

Relationships

NameTypeRequiredDescription
accountto-one (Account)⚪ No (nullable)The bank account this balance snapshot belongs to. FK: account_pk → core_api.accounts.pk. ON UPDATE CASCADE / ON DELETE SET NULL. Indexed via idx_account_balances_account. Also part of the partial index idx_account_balances_current for current-balance lookups.
workspaceto-one (Workspace)⚪ No (nullable)Tenant scope. FK: workspace_pk → core_api.workspaces.pk. ON UPDATE CASCADE / ON DELETE SET NULL. Every query must filter by workspace. Indexed together with deleted_at in idx_account_balances_workspace_deleted for Hasura permission filter hot-path.
transactionsto-many (Transaction)All Transaction records that fall within this balance period. Inverse of Transaction.account_balance (FK: transactions.account_balance_pk). A single AccountBalance can hold zero to many transactions. Used by composites such as composite_total_amount_currency on the accounts root.

System-computed

  • account_balance_id: generated by PostgreSQL gen_random_uuid() on INSERT (defaultRaw). Unique constraint enforced at the database level.
  • created_at: set to new Date() by the MikroORM onCreate lifecycle hook; never writable by the API consumer.
  • updated_at: set to new Date() on both onCreate and onUpdate by MikroORM lifecycle hooks.
  • deleted_at: null on creation; set by the application soft-delete pattern. All active-record queries filter WHERE deleted_at IS NULL.
  • Partial index idx_account_balances_current on (account_pk, balance_at_from DESC, pk DESC) WHERE balance_at_to IS NULL AND deleted_at IS NULL — enables an index-only scan with LIMIT 1 for the ‘current balance’ lookup pattern.
  • Partial index idx_account_balances_workspace_deleted on (workspace_pk, deleted_at) — optimises the Hasura permission filter (workspace_pk = $1 AND deleted_at IS NULL) on the hot read path.
  • verification_error, verification_error_detail, calculated_balance_diff, expected_balance_diff, verified_at, verification_last_run_at: all populated exclusively by the reconciliation pipeline; never set by the ingestion connector or by edge API writes.
  • raw_data: written once by the ingestion connector at sync time; treated as an immutable audit trail. Shape is connector-specific (e.g. Plaid account/balance JSON).
  • accounting_balance and foreign_exchange: written by the connector sync pipeline from provider-native balance data. Not editable via the public API.

Example

{
  "data": {
    "type": "account_balance",
    "id": "c3f8d2a1-4e57-4b2c-9a1d-88f702b63c14",
    "attributes": {
      "account_balance_id": "c3f8d2a1-4e57-4b2c-9a1d-88f702b63c14",
      "accounting_balance": {
        "opening_booked": 142500.00,
        "opening_value": 142500.00,
        "closing_booked": 138920.50,
        "closing_value": 138920.50,
        "currency": "EUR"
      },
      "foreign_exchange": [
        {
          "currency_rate": 1.0832,
          "currency_pair": "EUR/USD",
          "currency_rate_source": "ECB",
          "currency_rate_at": "2026-05-31T00:00:00.000Z"
        }
      ],
      "balance_at_from": "2026-05-01T00:00:00.000Z",
      "balance_at_to": "2026-05-31T23:59:59.000Z",
      "verified_at": "2026-06-01T06:15:22.000Z",
      "verification_error": false,
      "verification_error_detail": null,
      "calculated_balance_diff": 0,
      "expected_balance_diff": 0,
      "verification_last_run_at": "2026-06-01T06:15:22.000Z",
      "raw_data": null,
      "created_at": "2026-05-01T04:00:12.000Z",
      "updated_at": "2026-06-01T06:15:22.000Z",
      "deleted_at": null
    },
    "relationships": {
      "account": {
        "data": { "type": "account", "id": "a1b2c3d4-0001-4000-8000-000000000001" }
      },
      "workspace": {
        "data": { "type": "workspace", "id": "w9f8e7d6-0001-4000-8000-000000000001" }
      },
      "transactions": {
        "data": [
          { "type": "transaction", "id": "t0000001-0001-4000-8000-000000000001" },
          { "type": "transaction", "id": "t0000002-0001-4000-8000-000000000002" }
        ]
      }
    }
  }
}
Source: apps/api/src/database/entities/AccountBalance.ts · domain: financial-graph · tier: Supporting