# Retrieve a trial balance

Operation ID: `searchTrialBalance`

Group: Accounting › Reports › Trial Balances

[Open in the interactive reference](https://docs.api.lensing.ai/lensing/v1/endpoints/searchTrialBalance)

`POST /accounting/reports/trial-balance/search`

Read-only: A read that takes its filters in the body. Changes nothing, and ignores Idempotency-Key.

Retrieves the trial balance for one legal entity, book, and date range. The response has one item per account with a balance or a movement between startDate and endDate. The items cover the whole chart of accounts, so they include grouping accounts as well as the accounts below them.

A grouping account's figures repeat the sums of the accounts below it. To add up the report, sum only the items where isGroupingAccount is false, or use totals.

The report is not paginated, because a partial page would not balance.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Api-Version` | header | string · v1 | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version `v1`. |

## Request body

Required, `application/json`: searchTrialBalanceInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `entityId` | string | yes | The entity to report on. When consolidated is false, only this entity's own postings are included. When true, this is the consolidating parent and the report covers its whole hierarchy. Exactly one entity per request. See id on GET base/entities. Example: `"ebbe16c9-2c44-4a8e-a813-6ed5a78ffab3"`. |
| `bookId` | string | yes | The accounting book to report on. It must belong to entityId. A book that belongs to another entity is reported as BOOK_NOT_FOUND. Exactly one book per request, because balances from different books are not comparable. See id on GET accounting/books/:id. Example: `"8d534b26-2998-40dd-8727-9fe3f89ff503"`. |
| `consolidated` | boolean | yes | Whether to return the consolidated trial balance for entityId and its hierarchy. When true, subsidiary balances are translated into the parent's currency and intercompany eliminations are applied. When false, only this entity's own trial balance is returned, with no translation and no elimination. Example: `false`. |
| `startDate` | date | yes | The inclusive start of the reporting window. Format YYYY-MM-DD. functionalStartingBalance is the position immediately before this date. Interpreted on the axis named by dateAxis. Example: `"2025-01-01"`. |
| `endDate` | date | yes | The inclusive end of the reporting window. Format YYYY-MM-DD. functionalEndingBalance is the position at the close of this date. Interpreted on the axis named by dateAxis. Example: `"2025-12-31"`. |
| `dateAxis` | any | yes | Which axis the reporting window is measured on. 'postingDate' counts a movement on the date it was booked, the axis audit and reconciliation want. 'accountingPeriod' counts it in the period it was booked into, where budget comparisons belong. There is no default, because the two axes genuinely disagree for a line booked into an earlier period. One of: `"postingDate"`, `"accountingPeriod"`. Example: `"postingDate"`. |

```json
{
  "entityId": "ebbe16c9-2c44-4a8e-a813-6ed5a78ffab3",
  "bookId": "8d534b26-2998-40dd-8727-9fe3f89ff503",
  "consolidated": false,
  "startDate": "2025-01-01",
  "endDate": "2025-12-31",
  "dateAxis": "postingDate"
}
```

## Response

`200` Success

Under `data` (searchTrialBalanceOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array<object> | yes | One row per account that has a balance or a movement in scope, ordered by account number. The rows are the whole chart of accounts, so read isGroupingAccount before summing. An empty array when no account has a balance or movement in the window. |
| `items[].accountId` | string | yes | The account this row reports on. See id on GET accounting/accounts/:id. Example: `"0383f7c4-6176-4dc3-89e7-48c49511070f"`. |
| `items[].accountNumber` | string | yes | The account number, as defined by the chart of accounts. Rows are ordered by it. Example: `"111101"`. |
| `items[].accountName` | string | no | The name of the account. Absent when the account has none recorded. Example: `"Chase Checking"`. |
| `items[].accountType` | string | no | The type of the account. Possible values: 'asset', 'liability', 'equity', 'income', 'costOfGoodsSold', 'expense', 'otherIncome', 'otherExpense'. Example: `"asset"`. |
| `items[].isGroupingAccount` | boolean | yes | Whether this is a grouping (rollup) account. Its four figures are the sums of its descendants and are already counted in its children's rows, so sum only the rows where this is false, or use totals. Example: `false`. |
| `items[].parentAccountId` | string | no | The grouping account this row rolls up into. Absent at the root of the chart of accounts. See id on GET accounting/accounts/:id. Example: `"64e38cef-4809-47b8-b014-59065920d070"`. |
| `items[].functionalStartingBalance` | decimal | yes | The account's balance immediately before startDate, in reportingCurrency. Positive is a debit balance, negative a credit balance. Zero at the start of a fiscal year for an income or expense account, because the year-end rollover moves the prior year's result into retained earnings. Example: `"0"`. |
| `items[].functionalDebit` | decimal | yes | Total debit movements within the window, in reportingCurrency. Always present, and zero when there was no movement. Never negative, because a reversal is booked as a credit. Example: `"5000701.99"`. |
| `items[].functionalCredit` | decimal | yes | Total credit movements within the window, in reportingCurrency. Always present, and zero when there was no movement. Never negative. Example: `"503350.02"`. |
| `items[].functionalEndingBalance` | decimal | yes | The account's balance at the close of endDate, in reportingCurrency. functionalEndingBalance = functionalStartingBalance + functionalDebit - functionalCredit. Example: `"4497351.97"`. |
| `totals` | object | yes | The report's column totals, in reportingCurrency, summed over the leaf rows only. functionalDebit and functionalCredit here are the two figures a trial balance compares. |
| `totals.functionalStartingBalance` | decimal | yes | The sum of functionalStartingBalance over the leaf rows. Zero in a balanced ledger. Example: `"0"`. |
| `totals.functionalDebit` | decimal | yes | The sum of functionalDebit over the leaf rows. Equals functionalCredit when the report ties out. Example: `"6156388.01"`. |
| `totals.functionalCredit` | decimal | yes | The sum of functionalCredit over the leaf rows. Example: `"6156388.01"`. |
| `totals.functionalEndingBalance` | decimal | yes | The sum of functionalEndingBalance over the leaf rows. Zero in a balanced ledger. Example: `"0"`. |
| `tiesOut` | boolean | yes | Whether totals.functionalDebit equals totals.functionalCredit, computed from the figures in this response. When false, the response is still returned in full, with a TRIAL_BALANCE_DOES_NOT_TIE_OUT warning. Example: `true`. |
| `reportingCurrency` | string | yes | The currency every amount in this response is expressed in. Format ISO 4217, for example 'USD'. When consolidated is false this is the entity's own functional currency, and when true it is the consolidating parent's. Example: `"USD"`. |

```json
{
  "data": {
    "items": [
      {
        "accountId": "0383f7c4-6176-4dc3-89e7-48c49511070f",
        "accountNumber": "111101",
        "accountName": "Chase Checking",
        "accountType": "asset",
        "isGroupingAccount": false,
        "parentAccountId": "64e38cef-4809-47b8-b014-59065920d070",
        "functionalStartingBalance": "0",
        "functionalDebit": "5000701.99",
        "functionalCredit": "503350.02",
        "functionalEndingBalance": "4497351.97"
      }
    ],
    "totals": {
      "functionalStartingBalance": "0",
      "functionalDebit": "6156388.01",
      "functionalCredit": "6156388.01",
      "functionalEndingBalance": "0"
    },
    "tiesOut": true,
    "reportingCurrency": "USD"
  },
  "diagnostics": [
    {
      "code": "TRIAL_BALANCE_DOES_NOT_TIE_OUT",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": {
        "functionalDebit": "19.99",
        "functionalCredit": "19.99",
        "difference": "19.99"
      }
    }
  ]
}
```

## Errors

| Code | Status |
| --- | --- |
| `INVALID_DATE_RANGE` | 400 |
| `ENTITY_NOT_FOUND` | 400 |
| `BOOK_NOT_FOUND` | 400 |
| `CONSOLIDATION_ACCOUNT_MAPPING_MISSING` | 400 |
| `CONSOLIDATION_RATES_NOT_CONFIGURED` | 400 |
| `EXCHANGE_RATE_NOT_FOUND` | 400 |
| `TRIAL_BALANCE_CALCULATION_FAILED` | 400 |

## Advisories

Warnings and information a successful response can carry under `diagnostics`:

- `TRIAL_BALANCE_DOES_NOT_TIE_OUT`
- `EMPTY_REPORT`

## Statuses

- `400` — Invalid request or business failure. Codes: INVALID_DATE_RANGE, ENTITY_NOT_FOUND, BOOK_NOT_FOUND, CONSOLIDATION_ACCOUNT_MAPPING_MISSING, CONSOLIDATION_RATES_NOT_CONFIGURED, EXCHANGE_RATE_NOT_FOUND, TRIAL_BALANCE_CALCULATION_FAILED
- `401` — The request carries no valid access token.
- `403` — Not authorized
- `404` — Not found
- `429` — Too many requests from this client address. The response has no body and no `Retry-After` header.
- `500` — Internal server error
