# Business Made · Books

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /business-made/books/accounts

**List accounts**

`operationId: BooksController_listAccounts`

The chart of accounts — every ledger account and its type.

#### Signature

```http
GET /business-made/books/accounts () -> Accounts
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/ledger/{accountCode}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Accounts |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/accounts

**Create an account**

`operationId: BooksController_createAccount`

Adds an account to the chart. Its type determines which side of the balance sheet it falls on, so it cannot be sensibly changed once entries are posted to it.

#### Signature

```http
POST /business-made/books/accounts (body) -> The created account
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/accounts/update`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The account to create.

```json
{
  "code": "5100",
  "name": "Cost of goods sold",
  "type": "expense"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created account |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/accounts/{id}

**Get an account**

`operationId: BooksController_getAccount`

Fetches one ledger account.

#### Signature

```http
GET /business-made/books/accounts/{id} (id: string) -> The account
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/ledger/{accountCode}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The account |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/accounts/update

**Update an account**

`operationId: BooksController_updateAccount`

Updates an account. Renaming is safe; changing its `type` after entries exist changes how every historical report treats it.

#### Signature

```http
POST /business-made/books/accounts/update (body) -> The updated account
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Avoid changing `type` on an account that already has postings.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/trial-balance`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The account to update.

```json
{
  "id": "ACC-5100",
  "name": "Cost of sales"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated account |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/journals

**List journals**

`operationId: BooksController_listJournals`

Journal entries, drafted and posted.

#### Signature

```http
GET /business-made/books/journals (businessLocationId?: string, status?: string, page?: integer, pageSize?: integer) -> Journals
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- No date filter is applied: `from`/`to` are not read.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/journals/{id}/post`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `businessLocationId` | query | string | — | Restrict to one location. |
| `status` | query | string | — |  |
| `page` | query | integer | — |  |
| `pageSize` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Journals |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/journals

**Create a journal**

`operationId: BooksController_createJournal`

Creates a journal entry as a **draft**. Nothing reaches the ledger and no report moves until it is posted.

Entries are double-entry: debits and credits must balance.

#### Signature

```http
POST /business-made/books/journals (body) -> The draft journal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Drafting affects nothing — `post` is the step that moves the books.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/journals/{id}/post`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The journal to create.

```json
{
  "date": "2026-09-30",
  "memo": "Accrue September rent",
  "lines": [
    {
      "accountCode": "6100",
      "debit": 4500
    },
    {
      "accountCode": "2100",
      "credit": 4500
    }
  ]
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The draft journal |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/journals/{id}

**Get a journal**

`operationId: BooksController_getJournal`

Fetches one journal entry with its lines.

#### Signature

```http
GET /business-made/books/journals/{id} (id: string) -> The journal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/journals/{id}/post`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The journal |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/journals/{id}/post

**Post a journal**

`operationId: BooksController_postJournal`

Posts a draft journal to the ledger. **This moves the books** — balances change and reports for the period shift.

Correcting a posted entry means a reversing journal, not an edit, which is what keeps the ledger auditable.

#### Signature

```http
POST /business-made/books/journals/{id}/post (id: string) -> The posted journal
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Correct by reversing, never by editing a posted entry.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/trial-balance`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `id` | path | string | yes | Record id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The posted journal |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/ledger/{accountCode}

**Get an account ledger**

`operationId: BooksController_ledger`

Every line posted against an account (posted or reconciled journals; the code matches by prefix, so `1110` also matches `1110 Operating`), with a running balance — the drill-down behind a figure on a report. Reads up to 1,000 journals.

#### Signature

```http
GET /business-made/books/ledger/{accountCode} (accountCode: string, businessLocationId?: string) -> { accountCode, lines: [{ date, ref, memo, businessLocationId, debit, credit, running }], totalDebit, totalCredit, endingBalance }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- No date filter is applied: `from`/`to` are not read.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/trial-balance`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `accountCode` | path | string | yes | Account code (prefix match). |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | { accountCode, lines: [{ date, ref, memo, businessLocationId, debit, credit, running }], totalDebit, totalCredit, endingBalance } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/ar

**Get accounts receivable**

`operationId: BooksController_ar`

What customers owe, optionally by location — the receivables position from the ledger rather than from invoices.

#### Signature

```http
GET /business-made/books/ar (businessLocationId?: string) -> Accounts receivable
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/bills/aging`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `businessLocationId` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Accounts receivable |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/overview

**Get a books overview**

`operationId: BooksController_overview`

Headline financial position — the summary a dashboard reads.

#### Signature

```http
GET /business-made/books/overview (businessLocationId?: string, fromDate?: string, toDate?: string) -> Books overview
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/pl`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `businessLocationId` | query | string | — | Restrict to one location. |
| `fromDate` | query | string | — |  |
| `toDate` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Books overview |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/pl

**Get the profit and loss report**

`operationId: BooksController_pl`

Income and expenses for a period. Figures include only **posted** journals — a draft entry is invisible here.

#### Signature

```http
GET /business-made/books/reports/pl (from?: string, to?: string, businessLocationId?: string, groupByLocation?: boolean) -> The P&L report
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/pl/pdf`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `from` | query | string | — | Start of the period (YYYY-MM-DD). Also accepted as `fromDate` or `startDate`. Default: the first of this month. |
| `to` | query | string | — | End of the period. Also accepted as `toDate` or `endDate`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |
| `groupByLocation` | query | boolean | — | Split each line by location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The P&L report |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/balance-sheet

**Get the balance sheet**

`operationId: BooksController_bs`

Assets, liabilities and equity at a point in time.

#### Signature

```http
GET /business-made/books/reports/balance-sheet (asOfDate?: string, businessLocationId?: string) -> The balance sheet
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/balance-sheet/pdf`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `asOfDate` | query | string | — | The date the report is taken at (YYYY-MM-DD). Also accepted as `asOf` or `date`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The balance sheet |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/cash-flow

**Get the cash flow report**

`operationId: BooksController_cf`

Cash movement for a period — distinct from profit, which is what makes it worth reading separately.

#### Signature

```http
GET /business-made/books/reports/cash-flow (from?: string, to?: string, businessLocationId?: string) -> The cash flow report
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/pl`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `from` | query | string | — | Start of the period (YYYY-MM-DD). Also accepted as `fromDate` or `startDate`. Default: the first of this month. |
| `to` | query | string | — | End of the period. Also accepted as `toDate` or `endDate`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The cash flow report |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/close-check

**Run month-end close checks**

`operationId: BooksController_closeCheck`

Runs the checks that should pass before a period is closed — unbalanced entries, unposted drafts and accounts that look wrong.

Run this before locking a period: once locked, fixing anything means reopening, which is visible in the audit trail.

#### Signature

```http
GET /business-made/books/reports/close-check (from?: string, to?: string, businessLocationId?: string) -> Close check results
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/period-close/{id}/lock`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `from` | query | string | — | Start of the period (YYYY-MM-DD). Also accepted as `fromDate` or `startDate`. Default: the first of this month. |
| `to` | query | string | — | End of the period. Also accepted as `toDate` or `endDate`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Close check results |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/trial-balance

**Get the trial balance**

`operationId: BooksController_tb`

Every account with its debit and credit totals. If it does not balance, something is wrong at the ledger level — check this before closing a period.

#### Signature

```http
GET /business-made/books/reports/trial-balance (asOfDate?: string, businessLocationId?: string) -> The trial balance
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/close-check`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `asOfDate` | query | string | — | The date the report is taken at (YYYY-MM-DD). Also accepted as `asOf` or `date`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The trial balance |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/by-location

**Get financials by location**

`operationId: BooksController_perLocation`

Financial performance split by business location — where a multi-site operation is actually making or losing money.

#### Signature

```http
GET /business-made/books/reports/by-location (from?: string, to?: string) -> Per-location figures
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/pl`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `from` | query | string | — | Start of the period (YYYY-MM-DD). Also accepted as `fromDate` or `startDate`. Default: the first of this month. |
| `to` | query | string | — | End of the period. Also accepted as `toDate` or `endDate`. Default: today. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Per-location figures |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/pl/pdf

**Download the P&L as PDF**

`operationId: BooksController_plPdf`

The profit and loss report rendered as a PDF.

#### Signature

```http
GET /business-made/books/reports/pl/pdf (from?: string, to?: string, businessLocationId?: string) -> The P&L PDF
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/pl`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `from` | query | string | — | Start of the period (YYYY-MM-DD). Also accepted as `fromDate` or `startDate`. Default: the first of this month. |
| `to` | query | string | — | End of the period. Also accepted as `toDate` or `endDate`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The P&L PDF |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/reports/balance-sheet/pdf

**Download the balance sheet as PDF**

`operationId: BooksController_bsPdf`

The balance sheet rendered as a PDF.

#### Signature

```http
GET /business-made/books/reports/balance-sheet/pdf (asOfDate?: string, businessLocationId?: string) -> The balance sheet PDF
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | — | fromDate "<value>" is not a date — use YYYY-MM-DD | A period or as-of date does not parse. | — |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/balance-sheet`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `asOfDate` | query | string | — | The date the report is taken at (YYYY-MM-DD). Also accepted as `asOf` or `date`. Default: today. |
| `businessLocationId` | query | string | — | Restrict to one location. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The balance sheet PDF |
| `400` | fromDate "<value>" is not a date — use YYYY-MM-DD — A period or as-of date does not parse. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/account-map

**Get the account map**

`operationId: PostingController_getAccountMap`

How business events map to ledger accounts — which account a sale, refund or payment posts to. This mapping is what makes automatic posting possible.

#### Signature

```http
GET /business-made/books/account-map () -> The account map
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/account-map`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The account map |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/account-map

**Update the account map**

`operationId: PostingController_setAccountMap`

Changes how business events post to accounts. **Applies to future postings only** — historical entries keep the accounts they were posted to, so a mapping change makes period-over-period comparisons discontinuous.

#### Signature

```http
POST /business-made/books/account-map (body) -> The updated map
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Existing postings are not remapped.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/backfill`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The mapping to store.

```json
{
  "sale": {
    "revenue": "4000",
    "tax": "2200"
  },
  "refund": {
    "revenue": "4000"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The updated map |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/backfill

**Backfill ledger postings**

`operationId: PostingController_backfill`

Generates ledger postings for historical transactions that were never posted — the recovery path after a mapping was missing or the posting pipeline was down.

It writes real journal entries across a date range, so it moves historical reports. Check the trial balance before and after.

#### Signature

```http
POST /business-made/books/backfill (body) -> The backfill result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Re-running over a range that already posted will double-count. Verify coverage first.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/balance-drift`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

What to backfill.

```json
{
  "from": "2026-08-01",
  "to": "2026-08-31"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The backfill result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/backfill-cogs

**Backfill cost of goods sold**

`operationId: PostingController_backfillCogs`

Generates missing cost-of-goods postings for historical sales — the counterpart to revenue backfill, for when margin is understated because cost was never posted.

#### Signature

```http
POST /business-made/books/backfill-cogs (body) -> The backfill result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Same double-count risk as `backfill` — check what is already posted.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/backfill`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

What to backfill.

```json
{
  "from": "2026-08-01",
  "to": "2026-08-31"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The backfill result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/resume-postings

**Resume postings**

`operationId: PostingController_resumePostings`

Restarts the automatic posting pipeline after it was stopped or stalled. Check `balance-drift` afterwards to confirm nothing was missed while it was down.

#### Signature

```http
POST /business-made/books/resume-postings (body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/balance-drift`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Optional options.

```json
{}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/post/sale

**Post a sale**

`operationId: PostingController_postSale`

Posts a sale to the ledger using the account map. Normally driven automatically — call it directly only to record something the pipeline missed.

#### Signature

```http
POST /business-made/books/post/sale (body) -> The posting result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Not idempotent — posting the same sale twice double-counts revenue.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/post/refund`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The sale to post.

```json
{
  "orderNumber": "A7K2M9QX4",
  "amount": 129.99,
  "tax": 10.4,
  "date": "2026-09-15"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The posting result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/post/refund

**Post a refund**

`operationId: PostingController_postRefund`

Posts a refund to the ledger, reversing the revenue recognised on the original sale.

#### Signature

```http
POST /business-made/books/post/refund (body) -> The posting result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/post/sale`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The refund to post.

```json
{
  "orderNumber": "A7K2M9QX4",
  "amount": 129.99,
  "date": "2026-09-20"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The posting result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/post/invoice

**Post an invoice**

`operationId: PostingController_postInvoice`

Posts an invoice to the ledger, recognising receivable and revenue.

#### Signature

```http
POST /business-made/books/post/invoice (body) -> The posting result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/post/payment`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The invoice to post.

```json
{
  "invoiceNumber": "INV-4821",
  "amount": 4200,
  "date": "2026-09-01"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The posting result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/post/payment

**Post a payment**

`operationId: PostingController_postPayment`

Posts a payment received, clearing the receivable raised by the invoice.

#### Signature

```http
POST /business-made/books/post/payment (body) -> The posting result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/ar`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The payment to post.

```json
{
  "invoiceNumber": "INV-4821",
  "amount": 4200,
  "date": "2026-09-25"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The posting result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/balance-drift

**Check for balance drift**

`operationId: PostingController_balanceDrift`

Compares each ledger account's cached balance with the balance its posted journal entries imply, and lists the accounts where they differ (beyond a small tolerance), with both figures and the difference. Read-only.

Drift means a cached balance was not updated with a posting. Reports read cached balances, so check this before a period close.

#### Signature

```http
GET /business-made/books/balance-drift () -> Drifted accounts
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/books/balance-drift/repair`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Drifted accounts |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/books/balance-drift/repair

**Repair balance drift**

`operationId: PostingController_repairDrift`

Rewrites the cached debit, credit and net balance of every drifted account from its posted journal entries. No journal entry is written or changed — the posted entries are the source of truth and the cache is brought back to them. Safe to run repeatedly.

#### Signature

```http
POST /business-made/books/balance-drift/repair () -> What was repaired
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/balance-drift`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | What was repaired |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/books/trial-balance

**Get the posting trial balance**

`operationId: PostingController_trialBalance`

The trial balance from the posting layer. Compare it against `reports/trial-balance` — a difference between them points at drift.

#### Signature

```http
GET /business-made/books/trial-balance () -> The trial balance
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/books/reports/trial-balance`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The trial balance |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

