> ## 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

> Managing payroll accounting and integrations

Nmbr provides accounting features to map every payroll component (earnings, deductions, benefits, reimbursements, statutory withholdings) to accounts in a business entity's Chart of Accounts, generate journal entries for each payroll, and export them to Xero or QuickBooks Online. This guide covers how accounting codes, routing rules, and integrations fit together.

For multi-dimensional cost allocation (splitting a line item across departments, projects, or locations), see the [Tagging & Journal Entry Tracking](/guides/advanced/tagging) guide.

## Accounting Codes

Accounting Codes map payroll components to accounts in the business entity's Chart of Accounts, so each payroll entry is recorded as an **expense**, a **liability**, or a **bank** movement.

Accounting Codes are created at the **Business Entity** level.

**Fields:**

| Field                | Required | Description                                             |
| -------------------- | -------- | ------------------------------------------------------- |
| `business_entity_id` | yes      | The Business Entity the accounting code belongs to.     |
| `title`              | yes      | Human-friendly name of the accounting code.             |
| `type`               | yes      | One of `expense`, `liability`, or `bank`.               |
| `code`               | optional | The numeric/accounting code from the Chart of Accounts. |
| `description`        | optional | 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 `subtype` (e.g. `salary`, `wage`)
* `business_preset_id`, the highest-specificity match, mutually exclusive with `type`/`subtype`
* a tag, for tag-scoped routing (covered in the [Tagging guide](/guides/advanced/tagging#accounting-code-rules))

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

#### Example: route all salary 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",
         "subtype": "salary",
         "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, and a more specific rule can supply one side while a broader rule supplies the other.

Within global rules, more specific rules win:

1. `business_preset_id`
2. `type` + `subtype`
3. `type`

Tag-scoped and tag-group-scoped rules take precedence over global rules. The full precedence model, including the tag dimension, is in the [Tagging guide](/guides/advanced/tagging#rule-precedence).

> 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.

## Business Entity accounting settings

Each Business Entity carries an `accounting_settings` object that holds its accounting configuration. Read and write these through `accounting_settings`. 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 when generating journal entries. Required to generate the payment entry.                                                    |
| `default_payroll_payable_accounting_code`      | The `liability` code used as the payroll payable row. Required to generate journal entries.                                                                      |
| `primary_tag_group`                            | The Tag Group that drives tag-scoped accounting code resolution. See the [Tagging guide](/guides/advanced/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>"
         }
     }'
```

Without the default bank and payroll payable codes, journal entries cannot be generated or exported.

## Journal Entries

For each payroll, Nmbr generates two payroll-level journal entries, plus a recording entry for each pay stub.

### 1) Payroll Recording (Accrual Entry)

* Recognises payroll **expenses** and corresponding **liabilities**.
* Ensures costs are recorded in the correct accounting period.
* **Debit:** Expense accounts (e.g. Wages Expense).
* **Credit:** Liability accounts (e.g. Payroll Payable, Tax Withheld Payable).

**Example (simplified):**

| Account              | Debit | Credit |
| -------------------- | ----- | ------ |
| Wages Expense        | 5,000 |        |
| Employer CPP Expense | 500   |        |
| Payroll Payable      |       | 5,500  |

### 2) Payroll Payment (Payment Entry)

* Reflects the actual **cash movement** when payroll and remittances are paid.
* **Debit:** Liability accounts (clearing what was accrued).
* **Credit:** Bank account.

**Example (simplified):**

| Account         | Debit | Credit |
| --------------- | ----- | ------ |
| Payroll Payable | 5,500 |        |
| Bank Account    |       | 5,500  |

### Pay stub recording entries

Alongside the two payroll-level entries, Nmbr generates a `pay_stub_recording` entry for each pay stub, holding the accrual detail for that single pay stub. These carry a `pay_stub` reference and are returned by the [Journal Entries API](/api-reference/journal-entries/list-journal-entries) with the payroll-level entries. Filter by `type` to narrow the list. Only the two payroll-level entries (`payroll_recording` and `payroll_payment`) are exported to the connected accounting platform.

### Tracking dimensions

When a line item is allocated across tags, each journal entry row carries the matched tags in its `dimension_1_tag`, `dimension_2_tag`, and `dimension_3_tag` fields, and the row is split per allocation. This breaks down payroll cost by department, project, or location. The tags are returned as stubs by default; resolve them with a nested expand such as `journal_entry_rows.dimension_1_tag`. See [Journal entry tracking dimensions](/guides/advanced/tagging#journal-entry-tracking-dimensions) and [Retrieving dimension tags](/guides/advanced/tagging#retrieving-dimension-tags) for the full model.

### Sample Journal Entry JSON

```json theme={null}
{
  "id": "<ulid>",
  "object": "journal_entry",
  "data": {
    "type": "payroll_recording",
    "title": "Payroll Accrual Entry",
    "payroll": {
      "id": "<ulid>",
      "object": "payroll",
      "links": {
        "self": "/payrolls/<ulid>"
      }
    },
    "pay_stub": null,
    "is_balanced": true,
    "total": 5403.62,
    "is_missing_line_item_accounting_codes": false,
    "is_missing_default_account_payable": false,
    "is_missing_default_bank_account": false,
    "posted_on": "2025-01-15T00:00:00.000000Z",
    "invalid_expense_types": [],
    "invalid_liability_types": [],
    "integrations": {
      "quickbooks": {
        "reference": null
      },
      "xero": {
        "reference": null
      }
    },
    "journal_entry_rows": {
      "object": "list",
      "data": [
        {
          "id": "<ulid>",
          "object": "journal_entry_row",
          "data": {
            "type": "debit",
            "amount": 5000,
            "code": "6000",
            "description": "Semi-Monthly Schedule #1 - Wages Expense",
            "account_code": {
              "id": "<ulid>",
              "object": "accounting_code",
              "links": {
                "self": "/accounting_codes/<ulid>"
              }
            },
            "dimension_1_tag": null,
            "dimension_2_tag": null,
            "dimension_3_tag": null,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
          },
          "links": {
            "self": null
          }
        },
        {
          "id": "<ulid>",
          "object": "journal_entry_row",
          "data": {
            "type": "debit",
            "amount": 403.62,
            "code": "6010",
            "description": "Semi-Monthly Schedule #1 - Employer Contributions Expense",
            "account_code": {
              "id": "<ulid>",
              "object": "accounting_code",
              "links": {
                "self": "/accounting_codes/<ulid>"
              }
            },
            "dimension_1_tag": null,
            "dimension_2_tag": null,
            "dimension_3_tag": null,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
          },
          "links": {
            "self": null
          }
        },
        {
          "id": "<ulid>",
          "object": "journal_entry_row",
          "data": {
            "type": "credit",
            "amount": 1930.24,
            "code": "2200",
            "description": "Semi-Monthly Schedule #1 - Statutory Withholdings Payable",
            "account_code": {
              "id": "<ulid>",
              "object": "accounting_code",
              "links": {
                "self": "/accounting_codes/<ulid>"
              }
            },
            "dimension_1_tag": null,
            "dimension_2_tag": null,
            "dimension_3_tag": null,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
          },
          "links": {
            "self": null
          }
        },
        {
          "id": "<ulid>",
          "object": "journal_entry_row",
          "data": {
            "type": "credit",
            "amount": 3473.38,
            "code": "2210",
            "description": "Semi-Monthly Schedule #1 - Net Pay Payable",
            "account_code": {
              "id": "<ulid>",
              "object": "accounting_code",
              "links": {
                "self": "/accounting_codes/<ulid>"
              }
            },
            "dimension_1_tag": null,
            "dimension_2_tag": null,
            "dimension_3_tag": null,
            "created_at": "2025-01-01T00:00:00.000000Z",
            "updated_at": "2025-01-01T00:00:00.000000Z"
          },
          "links": {
            "self": null
          }
        }
      ]
    },
    "created_at": "2025-01-01T00:00:00.000000Z",
    "updated_at": "2025-01-01T00:00:00.000000Z"
  },
  "links": {
    "self": "/journal_entries/<ulid>"
  }
}
```

> Journal entries can be retrieved via the [Journal Entries API](/api-reference/journal-entries/list-journal-entries).

### Validation flags

Before a journal entry can be exported it must be complete and balanced. Inspect these flags on the entry:

| Field                                   | Meaning                                               |
| --------------------------------------- | ----------------------------------------------------- |
| `is_balanced`                           | `false` if debits ≠ credits.                          |
| `is_missing_line_item_accounting_codes` | One or more line items lack codes.                    |
| `is_missing_default_account_payable`    | No default payroll payable code set.                  |
| `is_missing_default_bank_account`       | No default bank code set.                             |
| `invalid_expense_types`                 | List of `{ type, subtype }` missing an expense code.  |
| `invalid_liability_types`               | List of `{ type, subtype }` missing a liability code. |

To stop incomplete entries from reaching an approved payroll, enable `block_approval_on_incomplete_journal_entries` (or `block_approval_on_missing_export_identifiers`) on the Business Entity's `accounting_settings`.

## Accounting Integrations

Nmbr integrates with **Xero** and **QuickBooks Online** via OAuth 2.0. This imports a business entity's Chart of Accounts and tracking dimensions, and exports payroll journal entries automatically.

### Xero Integration

To set up a Xero integration, register for a Xero developer account and create an OAuth 2.0 application. Configure the redirect URI to:

`https://uni-api.nmbr.co/oauth/code`

Create a [Demo company](https://central.xero.com/s/article/Use-the-demo-company) in Xero to test the integration.

### QuickBooks Integration

To set up a QuickBooks integration, register for a QuickBooks developer account and create an OAuth 2.0 application. Configure the redirect URI to:

`https://uni-api.nmbr.co/oauth/code`

Create a [Demo company](https://quickbooks.intuit.com/learn-support/en-ca/help-article/small-business-processes/test-drive-quickbooks-online/L9C12ODlA_CA_en_CA) in QuickBooks to test the integration. When creating a testing application, select the "Sandbox" environment in QuickBooks.

### Setup Overview

1. Register an **OAuth 2.0 application** with the accounting platform.
2. Configure the **redirect URI**:
   ```
   https://uni-api.nmbr.co/oauth/code
   ```
3. Add the **client ID/secret** in the Nmbr Portal.
4. Connect the accounting platform in the Nmbr Portal.
5. **Sync** accounts and tracking dimensions, then **export** journals.

### Syncing accounting codes

After a client connects their accounting platform, import their Chart of Accounts into their Nmbr Business Entity:

```bash theme={null}
curl --request POST \
     --url 'https://sandbox.nmbr.co/services/payroll/integrations/xero/sync' \
     --header 'Authorization: Bearer <access_token>' \
     --data '{
       "business_entity_id": "<business_entity_id>",
       "sync": "accounting_codes"
     }'
```

Imported accounts are limited to `liability`, `expense`, and `bank` types.

### Syncing tracking dimensions

Accounting platforms also expose tracking dimensions (Xero tracking categories, QuickBooks classes, departments, and projects). Import them with the `category`, `department`, or `project` sync types. Each imported dimension becomes a Tag Group, and its values become Tags, ready to use for [tag allocation](/guides/advanced/tagging).

```bash theme={null}
curl --request POST \
     --url 'https://sandbox.nmbr.co/services/payroll/integrations/quickbooks/sync' \
     --header 'Authorization: Bearer <access_token>' \
     --data '{
       "business_entity_id": "<business_entity_id>",
       "sync": "department"
     }'
```

The set of dimensions available depends on the connected platform. List what a connection exposes with [`GET /integrations/{integration}/tracking_dimensions`](/api-reference/integrations/list-integration-tracking-dimensions).

### Exporting journal entries

To export a payroll's journal entries:

```bash theme={null}
curl --request POST \
     --url 'https://sandbox.nmbr.co/services/payroll/integrations/xero/sync' \
     --header 'Authorization: Bearer <access_token>' \
     --data '{
       "payroll_id": "<payroll_id>",
       "sync": "journal_entries"
     }'
```

**Validation requirements:**

* All line items must have valid accounting codes.
* The Business Entity must have default **bank** and **payroll payable** codes set.

## 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 }` tuples 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.

## Quickstart: Payroll → Accounting

1. **Configure Accounting Codes**
   Set up expense, liability, and bank accounts; set the Business Entity's default bank and payroll payable codes in `accounting_settings`.

2. **Define Accounting Code Rules**
   Route line items to expense and liability codes by type, subtype, preset, or tag.

3. **Connect Accounting Platform**
   OAuth into Xero or QuickBooks; sync the Chart of Accounts and tracking dimensions.

4. **Export Journals**
   Approve payroll in Nmbr; export the accrual and payment journal entries.
