> ## Documentation Index
> Fetch the complete documentation index at: https://docs.range.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Roll-forward balance reconciliation

> For a requested period, ties each account/asset line's opening balance observation plus in-between movements to its actual closing observation — transfers and trades alike. A trade's proceeds are attributed to whichever account in the trade's connection actually holds the asset received (not only the account the trade row is attributed to), so both legs of a trade tie; a quote or fee leg with no account anywhere in the connection is declared in declared_gaps rather than silently dropped. Each movement line is labeled by kind (transfer_in, transfer_out, trade_in, trade_out, trade_fee) alongside the net movements_quantity, supporting both a quantity-conservation reading and a flow reading. Each account's effective period (the real observation timestamps actually used) is returned alongside the requested period, and may differ per account. The movement-count cap is evaluated once per connection (not per account, since a widened read spans every sibling); an affected connection returns movements_truncated and no computed closing for every account in it, rather than a partial number. USD accompanies each line for display only; it is never part of the identity or difference. Opening/closing balances and movements are both filtered through the workspace's token whitelist, per asset leg, so a hidden token cannot manufacture a phantom break on one side only; pass show_all=true to bypass filtering on both sides. account_ids can be narrowed further with the group_id, provider, network, account_type, role, and connection_id filters — a requested id failing any provided filter is dropped from the statement the same way an id outside the caller's workspace already is. reporting_currency accepts only USD today (no FX conversion exists yet); any other value is rejected.



## OpenAPI

````yaml /api-reference/platform-api.json get /v2/reconciliation/roll-forward
openapi: 3.0.0
info:
  title: Range Platform API
  description: >-
    The Range Platform API for workspace management, counterparties, and
    operational tooling.
  version: 1.7.21
  contact: {}
servers:
  - url: https://api.range.org
    description: Range API Server
security:
  - Authorization: []
  - Authorization: []
tags:
  - name: Address Information
    description: Get information about a crypto address.
  - name: Transfer Enrichments
    description: Attach workspace-scoped notes and categories to transfers.
  - name: Counterparties
    description: Manage external entities, their addresses, bank accounts, and documents.
paths:
  /v2/reconciliation/roll-forward:
    get:
      tags:
        - Reconciliation
      summary: Roll-forward balance reconciliation
      description: >-
        For a requested period, ties each account/asset line's opening balance
        observation plus in-between movements to its actual closing observation
        — transfers and trades alike. A trade's proceeds are attributed to
        whichever account in the trade's connection actually holds the asset
        received (not only the account the trade row is attributed to), so both
        legs of a trade tie; a quote or fee leg with no account anywhere in the
        connection is declared in declared_gaps rather than silently dropped.
        Each movement line is labeled by kind (transfer_in, transfer_out,
        trade_in, trade_out, trade_fee) alongside the net movements_quantity,
        supporting both a quantity-conservation reading and a flow reading. Each
        account's effective period (the real observation timestamps actually
        used) is returned alongside the requested period, and may differ per
        account. The movement-count cap is evaluated once per connection (not
        per account, since a widened read spans every sibling); an affected
        connection returns movements_truncated and no computed closing for every
        account in it, rather than a partial number. USD accompanies each line
        for display only; it is never part of the identity or difference.
        Opening/closing balances and movements are both filtered through the
        workspace's token whitelist, per asset leg, so a hidden token cannot
        manufacture a phantom break on one side only; pass show_all=true to
        bypass filtering on both sides. account_ids can be narrowed further with
        the group_id, provider, network, account_type, role, and connection_id
        filters — a requested id failing any provided filter is dropped from the
        statement the same way an id outside the caller's workspace already is.
        reporting_currency accepts only USD today (no FX conversion exists yet);
        any other value is rejected.
      operationId: getRollForward
      parameters:
        - name: start_time
          required: true
          in: query
          description: Requested period start (ISO 8601).
          schema:
            format: date-time
            example: '2026-07-01T00:00:00Z'
            type: string
        - name: end_time
          required: true
          in: query
          description: Requested period end (ISO 8601).
          schema:
            format: date-time
            example: '2026-08-01T00:00:00Z'
            type: string
        - name: account_ids
          required: true
          in: query
          description: >-
            Comma-separated account ids (UUIDs) to reconcile. Ids outside the
            caller's workspace are silently dropped, as is any requested id that
            does not also match every filter dimension below — the filters
            narrow this list further, they never expand it. Accepts at most 100
            ids; a longer list is rejected with a 400 rather than processed. A
            non-UUID entry is also rejected with a 400 naming the field, rather
            than reaching the database (RNG-5847).
          schema:
            minItems: 1
            example: >-
              a1b2c3d4-e5f6-7890-abcd-ef1234567890,b2c3d4e5-f6a7-8901-bcde-f12345678901
            type: array
            items:
              type: string
              format: uuid
        - name: group_id
          required: false
          in: query
          description: >-
            Filter to accounts that belong to this group (account_groups.id). A
            non-UUID value is rejected with a 400 naming the field (RNG-5847).
          schema:
            type: string
            format: uuid
            example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        - name: provider
          required: false
          in: query
          description: Filter to accounts held under a connection of this provider.
          schema:
            example: utila
            type: string
            enum:
              - utila
              - kraken
              - binance
              - okx
              - bybit
              - bitget
              - gate
              - kucoin
              - plaid
              - squads
              - altitude
              - coinbase
              - realms
              - wise
              - safe
              - hyperliquid
              - cubist
              - privy
              - dfns
              - anchorage
              - revolut_business
              - turnkey
              - fordefi
              - coins_ph
              - fireblocks
              - pave_bank
              - copper
        - name: network
          required: false
          in: query
          description: Filter to accounts on this network (e.g. ethereum, solana, stellar).
          schema:
            type: string
            example: ethereum
        - name: account_type
          required: false
          in: query
          description: Filter to accounts of this account type.
          schema:
            example: exchange
            type: string
            enum:
              - eoa
              - multisig
              - contract
              - custodian
              - exchange
              - bank
              - defi
        - name: role
          required: false
          in: query
          description: Filter to accounts tagged with this free-text role.
          schema:
            example: treasury
            type: string
        - name: connection_id
          required: false
          in: query
          description: >-
            Filter to accounts under this connection id. A non-UUID value is
            rejected with a 400 naming the field (RNG-5847).
          schema:
            type: string
            format: uuid
            example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        - name: reporting_currency
          required: false
          in: query
          description: >-
            Currency the statement's quantities/USD figures are denominated in.
            Only 'USD' is supported today — no FX conversion exists yet, so any
            other value is rejected with a 400. Ships now so downstream
            consumers see the final request shape ahead of multi-currency
            support landing. Validated for membership against a known currency
            set, and bounded to a short length — an unsupported or oversized
            value is rejected with a message derived from the caller's own
            input.
          schema:
            default: USD
            example: USD
            type: string
        - name: show_all
          required: false
          in: query
          description: >-
            Restores every opening/closing balance line and movement to its
            unfiltered shape, ignoring the workspace token whitelist on both
            sides of the identity. Never mutates stored overrides.
          schema:
            default: false
            type: boolean
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RollForwardResponseDto'
        '400':
          description: >-
            Invalid query (e.g. start_time not before end_time, an unsupported
            reporting_currency, or a non-UUID
            account_ids/group_id/connection_id).
components:
  schemas:
    RollForwardResponseDto:
      type: object
      properties:
        requested_period:
          $ref: '#/components/schemas/ReconciliationPeriodDto'
        reporting_currency:
          type: string
          example: USD
          description: >-
            Currency every quantity/USD figure in this response is denominated
            in. Always 'USD' today — echoed back so downstream consumers can
            rely on the field once multi-currency support lands, without a
            breaking change (RNG-5665).
        items:
          type: array
          items:
            $ref: '#/components/schemas/AccountRollForwardStatementDto'
      required:
        - requested_period
        - reporting_currency
        - items
    ReconciliationPeriodDto:
      type: object
      properties:
        start_time:
          type: string
          example: '2026-07-01T00:00:00.000Z'
        end_time:
          type: string
          example: '2026-08-01T00:00:00.000Z'
      required:
        - start_time
        - end_time
    AccountRollForwardStatementDto:
      type: object
      properties:
        account_id:
          type: string
          example: acc-1
        status:
          type: string
          enum:
            - ok
            - no_observation
            - unreconcilable
          example: ok
          description: >-
            ok when both an opening and closing balance observation were found;
            no_observation when this account has no trustworthy observation at
            one or both boundaries; unreconcilable when this account cannot be
            reconciled for the requested period at all (see
            unreconcilable_reason). lines is empty for both non-ok statuses.
        effective_period:
          nullable: true
          description: >-
            Real observation timestamps actually used for this account — may
            differ from requested_period and from other accounts in the same
            request. null when no observation window was resolved.
          type: object
          allOf:
            - $ref: '#/components/schemas/ReconciliationPeriodDto'
        reconcilable_from:
          type: string
          nullable: true
          example: '2026-07-23T12:00:00.000Z'
          description: >-
            This account's reconcilable floor (RNG-5662) — the later of its
            movements floor (first synced transaction coverage) and its balance
            floor (the append-only cutover, or its first snapshot if later).
            null when the account is unreconcilable for a reason that does not
            depend on the period (its network's capability, or an unknown
            movements floor) — see unreconcilable_reason.
        unreconcilable_reason:
          type: string
          nullable: true
          enum:
            - network_reconciliation_unsupported
            - balance_source_unreadable
            - movements_floor_unknown
            - period_precedes_reconcilable_floor
            - movements_truncated
            - period_overlaps_unsynced_range
            - sibling_scan_incomplete
          example: null
          description: >-
            Why this account is unreconcilable, when status is unreconcilable.
            null otherwise — with one exception (RNG-6020):
            sibling_scan_incomplete can be set while status is still ok, for an
            account whose own data was fully read but its Connection's
            best-effort Sibling scan was not (see that value's own description
            for the remedy). lines/declared_gaps are populated as normal in that
            one case, not emptied the way status unreconcilable implies.
        lines:
          type: array
          items:
            $ref: '#/components/schemas/AssetRollForwardLineDto'
        declared_gaps:
          description: >-
            Trade legs attributed to this account whose counter-asset (quote or
            fee) has no account anywhere in this trade's connection (RNG-5663) —
            declared here rather than silently dropped. Always empty when status
            is not ok.
          type: array
          items:
            $ref: '#/components/schemas/DeclaredGapDto'
        unsynced_period:
          nullable: true
          example: null
          description: >-
            Set when unreconcilable_reason is period_overlaps_unsynced_range
            (RNG-5705): the range this account never fetched, because a sync run
            stopped at a hard cap without reaching down into existing coverage.
            Because the stored range is hull-merged across every opening for
            this account, it may also cover a genuinely-synced island between
            two disjoint holes — it means "no movement in this range can be
            relied upon", not "every instant here is missing". null otherwise,
            including for every account synced before this field existed.
          type: object
          allOf:
            - $ref: '#/components/schemas/ReconciliationPeriodDto'
      required:
        - account_id
        - status
        - lines
        - declared_gaps
    AssetRollForwardLineDto:
      type: object
      properties:
        asset:
          type: string
          example: USDC
          description: Asset symbol.
        opening_quantity:
          type: string
          example: '100.5'
          description: >-
            Quantity observed at the account's effective opening instant, as a
            decimal string.
        movements_quantity:
          type: string
          example: '20.25'
          description: >-
            Net movement quantity between the opening and closing observations
            (transfers and trades, IN/trade_in adds, OUT/trade_out/trade_fee
            subtracts) — drives computed_closing_quantity below.
        movements:
          description: >-
            The same movements, labeled by kind instead of netted — the flow
            reading. Only kinds that actually occurred in the period are
            present; summing every entry (with sign per kind) reproduces
            movements_quantity.
          type: array
          items:
            $ref: '#/components/schemas/MovementBreakdownLineDto'
        computed_closing_quantity:
          type: string
          nullable: true
          example: '120.75'
          description: >-
            opening_quantity + movements_quantity, computed by this endpoint.
            null when declared_gap_reason is set (RNG-5729) — bad or missing
            data for this line means there is nothing trustworthy to compute;
            never a fabricated number derived from treating unreadable data as
            zero.
        actual_closing_quantity:
          type: string
          example: '120.75'
          description: >-
            Quantity observed at the account's effective closing instant, as a
            decimal string.
        difference:
          type: string
          nullable: true
          example: '0'
          description: >-
            actual_closing_quantity - computed_closing_quantity, exact and
            untyped (never rounded or bucketed into a tolerance). null under the
            same condition as computed_closing_quantity above.
        declared_gap_reason:
          type: string
          nullable: true
          enum:
            - trade_quote_leg_unattributed
            - trade_fee_leg_unattributed
            - network_fees_unmodelled
            - unreadable_asset_amount
            - unresolved_asset_identity
            - no_balance_observed
            - trade_base_leg_unattributed
          example: null
          description: >-
            Set when this line's difference is a known, named gap rather than an
            unexplained break (RNG-5664) — today only network_fees_unmodelled,
            when this is the account network's native asset and the shortfall (a
            negative difference) is consistent with unmodelled gas. difference
            above still reports the exact, untyped value either way; this field
            only adds why it should not be typed as a break. null when the line
            has no declared explanation.
        opening_usd:
          type: string
          nullable: true
          example: '100.50'
          description: >-
            Display-only USD value at the opening instant. Never part of the
            identity or difference above.
        closing_usd:
          type: string
          nullable: true
          example: '120.75'
          description: >-
            Display-only USD value at the closing instant. Never part of the
            identity or difference above.
      required:
        - asset
        - opening_quantity
        - movements_quantity
        - movements
        - actual_closing_quantity
    DeclaredGapDto:
      type: object
      properties:
        reason:
          type: string
          enum:
            - trade_quote_leg_unattributed
            - trade_fee_leg_unattributed
            - network_fees_unmodelled
            - unreadable_asset_amount
            - unresolved_asset_identity
            - no_balance_observed
            - trade_base_leg_unattributed
          example: trade_quote_leg_unattributed
          description: >-
            Why this leg is declared here rather than appearing on any asset
            line — its asset has no account anywhere in this trade's connection
            (checked across every sibling account, not only the accounts
            requested this call).
        asset:
          type: string
          example: USDC
          description: Asset the leg was in.
        quantity:
          type: string
          example: '500.00'
          description: Unsigned magnitude that could not be attributed to any account.
        transaction_id:
          type: string
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
          description: The trade transaction this leg came from.
      required:
        - reason
        - asset
        - quantity
        - transaction_id
    MovementBreakdownLineDto:
      type: object
      properties:
        kind:
          type: string
          enum:
            - transfer_in
            - transfer_out
            - trade_in
            - trade_out
            - trade_fee
          example: trade_in
          description: >-
            Labels this contribution instead of netting it away, so the response
            supports both a quantity-conservation reading (the line's
            movements_quantity) and a flow reading (this breakdown).
            trade_in/trade_out are expressed from the perspective of the asset
            this line is for, not the trade's side — a BUY's base leg is
            trade_in on the base asset and trade_out on the quote asset.
        quantity:
          type: string
          example: '25.00'
          description: >-
            Unsigned magnitude for this kind, summed over the period. Sign is
            conveyed by kind, not by this value.
      required:
        - kind
        - quantity
  securitySchemes:
    Authorization:
      type: apiKey
      in: header
      name: X-API-KEY
      description: Authorization method required to allow user to access the api endpoints.

````