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

# Accounting Codes & Rules

> Map payroll components to a Chart of Accounts and route line items to codes automatically.

Accounting codes map your payroll to a Chart of Accounts. Accounting code rules assign those codes to line items automatically, so each payroll produces a complete journal entry.

## Accounting codes

Each accounting code represents one account in the business entity's Chart of Accounts and is typed as an **expense**, a **liability**, or a **bank** code.

<Accordion title="New to accounting codes?" icon="lightbulb">
  A business's **Chart of Accounts** is the list of accounts it tracks money in, each with a short reference like `6000` for Wages Expense. Accounting software often calls these **GL codes** (general ledger codes). An **accounting code** represents one of those accounts in Nmbr, typed **expense**, **liability**, or **bank**.
</Accordion>

Accounting codes are created at the **Business Entity** level. Create them through the API, or import them from a connected accounting platform's Chart of Accounts (see [Importing the Chart of Accounts](/guides/accounting/integrations#importing-the-chart-of-accounts)).

**Fields:**

| Field                | Required | Description                                                     |
| -------------------- | -------- | --------------------------------------------------------------- |
| `business_entity_id` | Yes      | The Business Entity the accounting code belongs to.             |
| `title`              | Yes      | Display name of the account (e.g. "Wages Expense").             |
| `type`               | Yes      | One of `expense`, `liability`, or `bank`.                       |
| `code`               | No       | The account's reference in the Chart of Accounts (e.g. `6000`). |
| `description`        | No       | Detailed description of the accounting code.                    |

See the [Accounting Codes](/api-reference/accounting-codes/list-accounting-codes) API reference for full details.

### Merging accounting codes

Duplicate codes can accumulate, often after importing a Chart of Accounts. Send the codes to absorb to [`POST /accounting_codes/{id}/merge`](/api-reference/accounting-codes/merge-accounting-codes) to merge them into one; their references are reassigned to the target code and the duplicates are removed. All codes in a merge must share the same `type` and Business Entity.

## Routing line items to accounts

**Accounting code rules** decide which expense and liability codes a line item receives. A rule is defined on a Business Entity and assigns an `expense_accounting_code` and a `liability_accounting_code` to the line items it matches.

A rule matches on any combination of:

* `type` (e.g. `earning`, `deduction`), optionally narrowed by `subtypes` (e.g. `salary`, `wage`)
* `business_preset_id`, the highest-specificity match, mutually exclusive with `type`/`subtypes`
* a tag (`tag_id`) or any tag from a group (`tag_group_id`), for tag-scoped routing. Tag-scoped rules match tags in the [primary tag group](/guides/accounting/tagging#primary-tag-group).

A rule with neither a tag nor a tag group is **global**: it routes every matching line item regardless of tags.

A global rule can also carry a **segment template** instead of an accounting code, to compose a custom code on the Journal Entry report. See [Journal Entry Segment Templates](/guides/accounting/segment-templates).

See the [Accounting Code Rules](/api-reference/accounting-code-rules/list-accounting-code-rules) API reference for full details.

### Covering several subtypes with one rule

`subtypes` is a set: one rule routes every line item whose subtype is a member of it, so a single code covering salary, wage and commission is one rule rather than three. Every subtype in the set must belong to the rule's `type` — a rule never spans more than one type, so a code that also catches deductions needs a second rule.

Sending `subtypes` replaces the whole set; there is no add-one or remove-one.

Two rules can carry the same subtype when they match different line items — one scoped to a tag and one global, or two scoped to different tags. What is rejected is a pair that would match the same line item: within one scope (the same tag, the same tag group, or both global) and one type, a subtype belongs to at most one rule, since nothing would decide which of them routes it.

<Info>
  **Deprecated:** `subtype` is replaced by `subtypes` and will be removed in a future release. It still reads and writes, meaning a one-member set, and is still returned as the set's first member. Sending it against a rule holding several subtypes is rejected rather than dropping the rest.
</Info>

### Example: route salary, wage and commission earnings

```bash theme={null}
curl --request POST \
     --url 'https://sandbox.nmbr.co/services/payroll/accounting_code_rules' \
     --header 'Content-Type: application/json' \
     --header 'Authorization: Bearer <access_token>' \
     --data '{
         "business_entity_id": "<business_entity_id>",
         "type": "earning",
         "subtypes": ["salary", "wage", "commission"],
         "expense_accounting_code_id": "<wages_expense_code_id>",
         "liability_accounting_code_id": "<payroll_payable_code_id>"
     }'
```

### Rule precedence

The expense and liability codes are resolved **independently**. A single line item can take its expense code from one rule and its liability code from another; each side walks the precedence order on its own and uses the first rule that supplies that code.

Rules are tried most-specific first. If no rule matches the line item at one precedence, the next precedence is tried:

| Precedence  | Fields set on the rule                | Example line item the rule matches                                                  |
| ----------- | ------------------------------------- | ----------------------------------------------------------------------------------- |
| 1 (highest) | `tag_id` + `business_preset_id`       | "Engineering" tag on a line item with the "Senior Developer Salary" business preset |
| 2           | `tag_id` + `type` + `subtypes`        | "Engineering" tag on a line item of type earning, subtype salary                    |
| 3           | `tag_id` + `type`                     | "Engineering" tag on any earning line item                                          |
| 4           | `tag_id`                              | "Engineering" tag on any line item                                                  |
| 5           | `tag_group_id` + `business_preset_id` | Any tag from "Department" on a line item with the "Senior Developer Salary" preset  |
| 6           | `tag_group_id` + `type` + `subtypes`  | Any tag from "Department" on a line item of type earning, subtype salary            |
| 7           | `tag_group_id` + `type`               | Any tag from "Department" on any earning line item                                  |
| 8           | `tag_group_id`                        | Any tag from "Department" on any line item                                          |
| 9           | `business_preset_id`                  | A line item with the "Senior Developer Salary" business preset                      |
| 10          | `type` + `subtypes`                   | A line item of type earning, subtype salary                                         |
| 11          | `type`                                | Any earning line item                                                               |
| 12 (lowest) | none (catch-all)                      | Any line item, when no other rule matches                                           |

The catch-all (precedence 12) is the default for line items no other rule matches. It is a single global rule, so you can set one default instead of one rule per type. Create it by leaving `tag_id`, `tag_group_id`, `type`, `subtypes`, and `business_preset_id` all unset. At most one catch-all exists per business entity.

Tag and tag-group tiers (precedences 1–8) apply only to tags in the primary tag group. See [Tagging](/guides/accounting/tagging) for how tags scope rules.

> Rules are re-evaluated whenever a draft payroll is recalculated, so rule changes take effect on the next calculation. Approved payrolls keep the codes they resolved at approval time.

The resolved codes appear on the rows of each payroll's [journal entries](/guides/accounting/journal-entries). When a line item resolves no code, the entry's [validation flags](/guides/accounting/journal-entries#validation-flags) name what's missing.

## Business Entity accounting settings

Each Business Entity carries an `accounting_settings` object that holds its accounting configuration. The matching top-level fields (`default_bank_accounting_code`, `default_payroll_payable_accounting_code`, `primary_tag_group`, `resolve_journal_entry_stat_withholdings`) are retained as deprecated aliases.

| Setting                                        | Description                                                                                                                                                      |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `default_bank_accounting_code`                 | The `bank` code used as the bank row on the payment entry. Without it, that row carries no accounting code.                                                      |
| `default_payroll_payable_accounting_code`      | The `liability` code used as the payroll payable row. Without it, that row carries no accounting code.                                                           |
| `primary_tag_group`                            | The Tag Group that drives tag-scoped accounting code resolution. See the [Tagging guide](/guides/accounting/tagging#primary-tag-group).                          |
| `resolve_journal_entry_stat_withholdings`      | When `true`, statutory withholdings are split across tracking dimensions derived from their source earnings. When `false`, each appears as a single unsplit row. |
| `block_approval_on_incomplete_journal_entries` | When `true`, payroll approval is blocked if any exportable journal entry row has no accounting code.                                                             |
| `block_approval_on_missing_export_identifiers` | When `true`, approval is blocked if any exportable row lacks an accounting code, or has one without the connected integration's external identifier.             |

Set the defaults by updating the Business Entity:

```bash theme={null}
curl --request PUT \
     --url 'https://sandbox.nmbr.co/services/payroll/business_entities/<business_entity_id>' \
     --header 'Content-Type: application/json' \
     --header 'Authorization: Bearer <access_token>' \
     --data '{
         "accounting_settings": {
             "default_bank_accounting_code_id": "<bank_code_id>",
             "default_payroll_payable_accounting_code_id": "<payroll_payable_code_id>"
         }
     }'
```

Journal entries still generate without the default bank and payroll payable codes, but they are incomplete: the bank and payable rows carry no accounting code, the entry's [validation flags](/guides/accounting/journal-entries#validation-flags) are raised, and the export is blocked.

## Deprecations

**GL Codes.** Nmbr previously supported a simplified **GL Code** entity, deprecated in favour of accounting codes. References to "GL Codes" in the API or docs are deprecated and will be removed in a future release.

**Fallback mappings.** Accounting codes previously carried `fallback_mappings`, a collection of `{ type, subtype }` pairs used to route line items with no explicit code. This is deprecated in favour of global [accounting code rules](#routing-line-items-to-accounts), which cover the same routing and more. The `fallback_mappings` field still reads and writes for backwards compatibility.
