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

# Payroll Data Requirements

> What Nmbr needs to create payees, approve payroll, and file at year end.

The data Nmbr requires changes as you move through the payroll lifecycle. A field that is optional when you create an employee can be mandatory before their payroll is approved, or before their [year-end forms](/guides/canada/year-end-tax-forms) are correct.

This guide covers what each field requires, when it becomes mandatory, and how to check values before you send them.

## When data is required

Few fields are required outright. Most become mandatory at a specific point:

| Requirement                   | What happens if it is missing                                                           |
| ----------------------------- | --------------------------------------------------------------------------------------- |
| Required to create            | The create request fails with a `422`.                                                  |
| Required to approve a payroll | The record is saved. Approving the payroll is blocked until you supply it.              |
| Expected for year end         | Payroll is unaffected. The T4 or RL-1 is incomplete and needs correcting before filing. |
| Required for automated filing | The agency rejects the submission when Nmbr transmits it.                               |

`sin` shows why the distinction matters. You can create an employee without a SIN and run payroll for the employee all year. Nmbr flags the gap with a warning, but nothing requires you to resolve it until the employee's T4 is generated in February, by which point they may have left. Date of birth and address behave the same way.

Nmbr treats all three as onboarding data. Nothing enforces them at that point, but they are far easier to capture during onboarding than at year end.

## Creating an employee

Only `first_name` and `last_name` are required.

**Request**

```bash theme={null}
curl --request POST \
     --url https://sandbox.nmbr.co/services/payroll/employees \
     --header 'Authorization: Bearer <access_token>' \
     --header 'content-type: application/json' \
     --data '{
        "first_name": "Kendall",
        "last_name": "Tremblay"
     }'
```

Nothing else is required at create.

| Field                              | When it's needed |
| ---------------------------------- | ---------------- |
| `first_name`                       | At create        |
| `last_name`                        | At create        |
| `employee_number`                  | Never            |
| `middle_initial`                   | Never            |
| `personal_email`, `work_email`     | Never            |
| [`sin`](#social-insurance-number)  | Year end         |
| `date_of_birth`                    | Year end         |
| `address_line_1`, `address_line_2` | Year end         |
| `city`                             | Year end         |
| `province_code`                    | Year end         |
| `postal_code`                      | Year end         |
| `country_code`                     | Year end         |
| `external_ref`                     | Never            |
| `preferred_locale`                 | Never            |

The full validation rules for each field are in the [API reference](/api-reference/employees/create-an-employee). Address fields carry length limits from the CRA T4 and RL-1 form specifications: 30 characters for each address line, 28 for city. Longer values are rejected rather than silently truncated on the form.

## Creating a contractor

A contractor is either a business or an individual, and needs enough to identify it as one. Send `business_name` for a business, or both `first_name` and `last_name` for an individual. A create request with neither is rejected.

**Request**

```bash theme={null}
curl --request POST \
     --url https://sandbox.nmbr.co/services/payroll/contractors \
     --header 'Authorization: Bearer <access_token>' \
     --header 'content-type: application/json' \
     --data '{
        "business_name": "Tremblay Consulting Inc."
     }'
```

The same rule applies on update, measured against the stored record. Omitting a name field leaves it as it is, and only a change that would remove every name is rejected.

Nothing else is required at create. What you need after that depends on the contractor.

| Field                                     | When it's needed                           |
| ----------------------------------------- | ------------------------------------------ |
| `business_name`                           | At create, unless you send both names      |
| `first_name`, `last_name`                 | At create, unless you send `business_name` |
| `middle_initial`                          | Never                                      |
| `email`                                   | Never                                      |
| [`business_number`](#cra-business-number) | Year end, for T4A reporting                |
| [`sin`](#social-insurance-number)         | Year end, for T4A reporting                |
| `external_ref`                            | Never                                      |
| `preferred_locale`                        | Never                                      |

Which of `business_number` and `sin` applies depends on the contractor. A corporation has a `business_number` and no `sin`. An individual is the opposite: a `sin` and no `business_number`.

## Tax and banking identifiers

Payroll depends on identifiers issued by tax agencies and banks. These are entered by hand, so most carry a check digit that makes a mistyped value detectably wrong rather than quietly accepted.

Nmbr applies these rules on write. The agencies publish them too, so the sections below describe each rule for you to apply in your own interface before sending a value.

### Social Insurance Number

A SIN is nine digits and carries a Luhn check digit.

* Send it as a string. Nmbr strips spaces and dashes before validating.
* The first digit cannot be `0` or `8`. Those ranges are not issued.
* The number must pass the [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm), a mod-10 checksum that catches single-digit typos and most transposed pairs.

Nmbr rejects a SIN that fails any of these with a `422`.

A SIN is not required to create an employee or to run payroll. It is required for a correct T4 or RL-1, and for a Record of Employment filed through ROE SAT, where the submission is validated on receipt and a missing SIN is rejected. See [Year End Tax Forms](/guides/canada/year-end-tax-forms) and [Record of Employment](/guides/canada/record-of-employment).

Reading an employee or contractor back returns `sin_last_3` rather than the full number, which is enough for someone to confirm they entered the right value. The full SIN is available from `GET /employees/<employee_id>/reveal` and `GET /contractors/<contractor_id>/reveal`, which carry a tighter rate limit than the rest of the API. See [Rate Limits](/api/overview/rate-limits).

### CRA Business Number

A CRA program account number is fifteen characters: a nine-digit business number, a two-letter program identifier, and a four-digit reference number.

```
123456782 RP 0001
└───────┘ └┘ └──┘
   root   │   reference
       program
```

* The root is nine digits and carries a Luhn check digit, the same algorithm as a SIN.
* The root begins with `1`, `7`, or `8`. The CRA does not issue others.
* `RP` is the payroll program. A CRA remittance account identifier must use it. A contractor's `business_number` may use a different program identifier.
* The reference number starts at `0001`. `0000` is never a real account.

For a business entity, this value is configured as the `account_identifier` on a CRA Remittance Account. A business entity can hold more than one. See [Tax Agency Configuration](/guides/payroll-fundamentals/tax-agency-configuration).

Nmbr validates the format wherever a business number is accepted, and validates the check digit when you create a ROE SAT agreement.

### Revenu Québec identification number

A Quebec identification number is sixteen characters: a ten-digit identifier, `RS`, and a four-digit file number. Nmbr validates all of the following.

* The ten-digit identifier carries a check digit.
* The first two digits are `10`, `12`, or in the range `40` to `59`.
* The file number is between `0001` and `9999`.
* The number is unique within the business entity.

For a business entity, this value is configured as the `account_identifier` on a Revenu Québec Remittance Account. A business entity can hold more than one. See [Tax Agency Configuration](/guides/payroll-fundamentals/tax-agency-configuration).

The check digit is a weighted mod-11 calculation, and not the same algorithm as the Luhn check used for SIN and CRA numbers.

### Bank accounts

Canadian bank details are three separate fields, each with a fixed length.

* `institution_number`: exactly three digits.
* `transit_number`: exactly five digits.
* `account_number`: 1 to 12 digits.

Nmbr rejects anything that is not digits, or is the wrong length, with a `422`.

Reading a bank account back returns `account_number_last_3` rather than the full number. The full value is available from `GET /bank_accounts/<bank_account_id>/reveal`, under the same tighter rate limit as the SIN reveal endpoints.

Nmbr also checks the account number against the account-number validation rules that Payments Canada publishes in its Standard 006 specification. Each institution defines its own rules, so this check only applies to institutions Nmbr holds rules for. A failure here does not reject the request.

**A `201` on a bank account is not confirmation the account is valid.** The account is saved, and a failed check appears as a warning on the record:

| Warning                                 | Meaning                                                                      |
| --------------------------------------- | ---------------------------------------------------------------------------- |
| `bank_account_unrecognized_institution` | The institution number is not one Nmbr recognises.                           |
| `bank_account_unrecognized_transit`     | The institution is known, but the transit is not a branch Nmbr holds for it. |
| `bank_account_invalid_account`          | The account number fails its institution's check-digit rules.                |

The `warnings` collection on the bank account carries these after you save. The lookup endpoint below returns the same ones before you save anything.

## Validating bank details

`POST /bank_accounts/lookup` runs the same institution, transit, and check-digit checks used on a saved account, and creates no record.

All three fields are optional, and each check runs only where the values it needs are present.

**Request**

```bash theme={null}
curl --request POST \
     --url https://sandbox.nmbr.co/services/payroll/bank_accounts/lookup \
     --header 'Authorization: Bearer <access_token>' \
     --header 'content-type: application/json' \
     --data '{
        "institution_number": "003",
        "transit_number": "00002",
        "account_number": "6284137"
     }'
```

**Response**

```json theme={null}
{
  "id": null,
  "object": "bank_account_lookup",
  "data": {
    "warnings": {
      "object": "list",
      "data": []
    },
    "institution_name": "Royal Bank of Canada",
    "institution_name_translations": {
      "en": "Royal Bank of Canada",
      "fr": "Banque Royale du Canada"
    },
    "institution_name_translated": "Royal Bank of Canada",
    "transit_address": "1 Place Ville Marie, Montreal, QC"
  },
  "links": {
    "self": null
  }
}
```

An empty `warnings` list means the details passed every check Nmbr can run. Anything in the list is the same warning the account would carry if you saved it.

`institution_name_translated` follows the request locale. See [Localization](/api/overview/localization).

## What blocks a payroll

[Warnings](/api/overview/warnings) tell you what data is missing. What one blocks depends on the record carrying it.

* Warnings on a **business entity** must all be resolved before the business can be approved, and an unapproved business cannot run payroll.
* Warnings on a **payroll or pay stub** are checked at approval, and each one blocks it.
* Warnings on an **employee, contractor, or bank account** do not block payroll.

[Warnings](/api/overview/warnings) lists every type with what resolves it.

A payroll may be approved and paid normally for an employee with no SIN, no date of birth, and no address. The gap surfaces at year end, on their T4. A payroll approved without warnings is not a signal that the employee record is complete.

Businesses in [preview mode](/guides/advanced/preview-mode) skip the remitter type and remittance account checks. [Historical payrolls](/guides/advanced/historical-payrolls) skip them too, so you can import prior-year data without full remittance setup.

### Other approval failures

Some approval failures are about state rather than missing data:

* The payroll is not in `draft` status.
* The payroll or any of its pay stubs is recalculating, shown by `is_stale` on both. Recalculation is usually brief.
* The approval deadline for the pay date has passed.
* An earlier **regular** payroll on the same schedule is still unapproved or unpaid. Regular payrolls approve in pay-date order.

Two more are set per business entity under `accounting_settings`, and default to off.

* `block_approval_on_incomplete_journal_entries`: an exportable journal entry row has no Accounting Code.
* `block_approval_on_missing_export_identifiers`: an exportable journal entry row has no Accounting Code, or has one without the enabled integration's external identifier.

See [Codes and Rules](/guides/accounting/codes-and-rules) and [Journal Entries](/guides/accounting/journal-entries).

## Handling validation failures

A failed request returns a `422` with an `errors` object keyed by field name. See [Responses](/api/overview/response-structure).

The field name and the status code are the stable parts of a failure. Messages are written for people. They get reworded as validation is refined, and are returned in the language you request.

```json theme={null}
{
  "message": "Not a valid SIN. It must be 9 digits.",
  "errors": {
    "sin": ["Not a valid SIN. It must be 9 digits."]
  }
}
```

To show these messages to someone in French, send an `Accept-Language` header. See [Localization](/api/overview/localization).
