# Create an accounting code rule Source: https://docs.nmbr.co/api-reference/accounting-code-rules/create-an-accounting-code-rule /spec/openapi.json post /accounting_code_rules # Delete an accounting code rule Source: https://docs.nmbr.co/api-reference/accounting-code-rules/delete-an-accounting-code-rule /spec/openapi.json delete /accounting_code_rules/{accounting_code_rule} # List accounting code rules Source: https://docs.nmbr.co/api-reference/accounting-code-rules/list-accounting-code-rules /spec/openapi.json get /accounting_code_rules # Retrieve an accounting code rule Source: https://docs.nmbr.co/api-reference/accounting-code-rules/retrieve-an-accounting-code-rule /spec/openapi.json get /accounting_code_rules/{accounting_code_rule} # Search accounting code rules Source: https://docs.nmbr.co/api-reference/accounting-code-rules/search-accounting-code-rules /spec/openapi.json post /accounting_code_rules/search Search a business entity's accounting code rules. The body is a filter set at the root, plus an optional `any_of` list of filter sets. The root set narrows every result; the `any_of` sets are combined with OR and then applied together with the root, so a rule matches when it satisfies the root set and at least one `any_of` entry. An empty body returns every rule for the business entity. A filter set has the same shape at the root and in each `any_of` entry: - A field group β€” `tag_groups`, `tags`, `types`, `subtypes`, `business_presets`, `expense_accounting_codes`, `liability_accounting_codes` β€” carries an `include` and/or `exclude` list of values. `include` matches rules whose field is one of the listed values; `exclude` matches rules whose field is none of them, keeping rules where the field is unset. - A `has_` boolean β€” `has_tag_group`, `has_tag`, `has_type`, `has_subtype`, `has_business_preset`, `has_expense_accounting_code`, `has_liability_accounting_code` β€” matches rules where the field is set (`true`) or unset (`false`). Field groups and presence booleans within a set combine with AND. # Update an accounting code rule Source: https://docs.nmbr.co/api-reference/accounting-code-rules/update-an-accounting-code-rule /spec/openapi.json put /accounting_code_rules/{accounting_code_rule} # Create an accounting code Source: https://docs.nmbr.co/api-reference/accounting-codes/create-an-accounting-code /spec/openapi.json post /accounting_codes # Delete an accounting code Source: https://docs.nmbr.co/api-reference/accounting-codes/delete-an-accounting-code /spec/openapi.json delete /accounting_codes/{accounting_code} # List accounting codes Source: https://docs.nmbr.co/api-reference/accounting-codes/list-accounting-codes /spec/openapi.json get /accounting_codes # Merge accounting codes Source: https://docs.nmbr.co/api-reference/accounting-codes/merge-accounting-codes /spec/openapi.json post /accounting_codes/{accounting_code}/merge Merge manual generated accounting codes into other codes. A manual code is any code that has no `xero_id` or `quickbooks_id`, which indicates it was imported from an external accounting platform. The manual codes will be deleted after reassignment, with all references to them updated to the target accounting code. # Retrieve an accounting code Source: https://docs.nmbr.co/api-reference/accounting-codes/retrieve-an-accounting-code /spec/openapi.json get /accounting_codes/{accounting_code} # Update an accounting code Source: https://docs.nmbr.co/api-reference/accounting-codes/update-an-accounting-code /spec/openapi.json put /accounting_codes/{accounting_code} # Create an adjustment Source: https://docs.nmbr.co/api-reference/adjustments/create-an-adjustment /spec/openapi.json post /adjustments # Delete an adjustment Source: https://docs.nmbr.co/api-reference/adjustments/delete-an-adjustment /spec/openapi.json delete /adjustments/{adjustment} # List adjustments Source: https://docs.nmbr.co/api-reference/adjustments/list-adjustments /spec/openapi.json get /adjustments # Retrieve an adjustment Source: https://docs.nmbr.co/api-reference/adjustments/retrieve-an-adjustment /spec/openapi.json get /adjustments/{adjustment} # Update an adjustment Source: https://docs.nmbr.co/api-reference/adjustments/update-an-adjustment /spec/openapi.json put /adjustments/{adjustment} # Batch delete allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/batch-delete-allowance-line-items /spec/openapi.json post /allowance_line_items/batch/delete # Batch upsert allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/batch-upsert-allowance-line-items /spec/openapi.json post /allowance_line_items/batch/upsert # Bulk create allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/bulk-create-allowance-line-items /spec/openapi.json post /allowance_line_items/bulk/create # Bulk delete allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/bulk-delete-allowance-line-items /spec/openapi.json post /allowance_line_items/bulk/delete # Bulk update allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/bulk-update-allowance-line-items /spec/openapi.json post /allowance_line_items/bulk/update # Create an allowance line item Source: https://docs.nmbr.co/api-reference/allowance-line-items/create-an-allowance-line-item /spec/openapi.json post /allowance_line_items # Delete an allowance line item Source: https://docs.nmbr.co/api-reference/allowance-line-items/delete-an-allowance-line-item /spec/openapi.json delete /allowance_line_items/{allowance_line_item} # List allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/list-allowance-line-items /spec/openapi.json get /allowance_line_items # Retrieve an allowance line item Source: https://docs.nmbr.co/api-reference/allowance-line-items/retrieve-an-allowance-line-item /spec/openapi.json get /allowance_line_items/{allowance_line_item} # Search allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/search-allowance-line-items /spec/openapi.json post /allowance_line_items/search Search line items under the given payroll, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/show-bulk-create-scope-for-allowance-line-items /spec/openapi.json post /allowance_line_items/bulk/create/scope # Show bulk delete scope for allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/show-bulk-delete-scope-for-allowance-line-items /spec/openapi.json post /allowance_line_items/bulk/delete/scope # Show bulk update scope for allowance line items Source: https://docs.nmbr.co/api-reference/allowance-line-items/show-bulk-update-scope-for-allowance-line-items /spec/openapi.json post /allowance_line_items/bulk/update/scope # Update an allowance line item Source: https://docs.nmbr.co/api-reference/allowance-line-items/update-an-allowance-line-item /spec/openapi.json put /allowance_line_items/{allowance_line_item} # List allowance types Source: https://docs.nmbr.co/api-reference/allowance-types/list-allowance-types /spec/openapi.json get /allowance_types # Batch delete allowances Source: https://docs.nmbr.co/api-reference/allowances/batch-delete-allowances /spec/openapi.json post /allowances/batch/delete # Batch upsert allowances Source: https://docs.nmbr.co/api-reference/allowances/batch-upsert-allowances /spec/openapi.json post /allowances/batch/upsert # Bulk create allowances Source: https://docs.nmbr.co/api-reference/allowances/bulk-create-allowances /spec/openapi.json post /allowances/bulk/create # Bulk delete allowances Source: https://docs.nmbr.co/api-reference/allowances/bulk-delete-allowances /spec/openapi.json post /allowances/bulk/delete # Bulk update allowances Source: https://docs.nmbr.co/api-reference/allowances/bulk-update-allowances /spec/openapi.json post /allowances/bulk/update # Create an allowance Source: https://docs.nmbr.co/api-reference/allowances/create-an-allowance /spec/openapi.json post /allowances # Delete an allowance Source: https://docs.nmbr.co/api-reference/allowances/delete-an-allowance /spec/openapi.json delete /allowances/{allowance} # List allowances Source: https://docs.nmbr.co/api-reference/allowances/list-allowances /spec/openapi.json get /allowances # Retrieve an allowance Source: https://docs.nmbr.co/api-reference/allowances/retrieve-an-allowance /spec/openapi.json get /allowances/{allowance} # Search allowances Source: https://docs.nmbr.co/api-reference/allowances/search-allowances /spec/openapi.json post /allowances/search Search allowances under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for allowances Source: https://docs.nmbr.co/api-reference/allowances/show-bulk-create-scope-for-allowances /spec/openapi.json post /allowances/bulk/create/scope # Show bulk delete scope for allowances Source: https://docs.nmbr.co/api-reference/allowances/show-bulk-delete-scope-for-allowances /spec/openapi.json post /allowances/bulk/delete/scope # Show bulk update scope for allowances Source: https://docs.nmbr.co/api-reference/allowances/show-bulk-update-scope-for-allowances /spec/openapi.json post /allowances/bulk/update/scope # Update an allowance Source: https://docs.nmbr.co/api-reference/allowances/update-an-allowance /spec/openapi.json put /allowances/{allowance} # Retrieve an async task Source: https://docs.nmbr.co/api-reference/async-tasks/retrieve-an-async-task /spec/openapi.json get /async_tasks/{async_task} Endpoint to fetch an AsyncTask. Async Tasks are created when a long-running process is initiated (e.g. form generation) and can be used to track the progress of that process and fetch the results once it is completed. A task starts as `processing` and ends as either `completed` or `error`. The `async_task_completed` webhook fires on both, whether the work succeeded or failed, so use this endpoint to read `status` and, on `error`, any failure details in `results`. `completed_at` is only set when the task succeeded. The following example is for a Form Generation task, but the response fields will differ depending on the specific AsyncTask instance requested. # Create a bank account Source: https://docs.nmbr.co/api-reference/bank-accounts/create-a-bank-account /spec/openapi.json post /bank_accounts # Delete a bank account Source: https://docs.nmbr.co/api-reference/bank-accounts/delete-a-bank-account /spec/openapi.json delete /bank_accounts/{bank_account} # List bank accounts Source: https://docs.nmbr.co/api-reference/bank-accounts/list-bank-accounts /spec/openapi.json get /bank_accounts # Look up bank account details Source: https://docs.nmbr.co/api-reference/bank-accounts/look-up-bank-account-details /spec/openapi.json post /bank_accounts/lookup # Retrieve a bank account Source: https://docs.nmbr.co/api-reference/bank-accounts/retrieve-a-bank-account /spec/openapi.json get /bank_accounts/{bank_account} # Reveal bank account number Source: https://docs.nmbr.co/api-reference/bank-accounts/reveal-bank-account-number /spec/openapi.json get /bank_accounts/{bank_account}/reveal # Show PAD Source: https://docs.nmbr.co/api-reference/bank-accounts/show-pad /spec/openapi.json get /bank_accounts/pad # Update a bank account Source: https://docs.nmbr.co/api-reference/bank-accounts/update-a-bank-account /spec/openapi.json put /bank_accounts/{bank_account} # Create a business entity Source: https://docs.nmbr.co/api-reference/business-entities/create-a-business-entity /spec/openapi.json post /business_entities # Delete a business entity Source: https://docs.nmbr.co/api-reference/business-entities/delete-a-business-entity /spec/openapi.json delete /business_entities/{business_entity} # End preview Source: https://docs.nmbr.co/api-reference/business-entities/end-preview /spec/openapi.json post /business_entities/{business_entity}/end_preview # List business entities Source: https://docs.nmbr.co/api-reference/business-entities/list-business-entities /spec/openapi.json get /business_entities If the `tax_properties` are expanded, only Tax Properties active on the current date will be returned. # Reset preview Source: https://docs.nmbr.co/api-reference/business-entities/reset-preview /spec/openapi.json post /business_entities/{business_entity}/reset_preview # Retrieve a business entity Source: https://docs.nmbr.co/api-reference/business-entities/retrieve-a-business-entity /spec/openapi.json get /business_entities/{business_entity} If the `tax_properties` are expanded, only Tax Properties active on the current date will be returned. # Update a business entity Source: https://docs.nmbr.co/api-reference/business-entities/update-a-business-entity /spec/openapi.json put /business_entities/{business_entity} # Create a business entity ROE authorization Source: https://docs.nmbr.co/api-reference/business-entity-roe-authorizations/create-a-business-entity-roe-authorization /spec/openapi.json post /business_entity_roe_authorizations # Delete a business entity ROE authorization Source: https://docs.nmbr.co/api-reference/business-entity-roe-authorizations/delete-a-business-entity-roe-authorization /spec/openapi.json delete /business_entity_roe_authorizations/{roe_authorization} # List business entity ROE authorizations Source: https://docs.nmbr.co/api-reference/business-entity-roe-authorizations/list-business-entity-roe-authorizations /spec/openapi.json get /business_entity_roe_authorizations # Retrieve a business entity ROE authorization Source: https://docs.nmbr.co/api-reference/business-entity-roe-authorizations/retrieve-a-business-entity-roe-authorization /spec/openapi.json get /business_entity_roe_authorizations/{roe_authorization} # Update a business entity ROE authorization Source: https://docs.nmbr.co/api-reference/business-entity-roe-authorizations/update-a-business-entity-roe-authorization /spec/openapi.json put /business_entity_roe_authorizations/{roe_authorization} # Retrieve a business entity verification Source: https://docs.nmbr.co/api-reference/business-entity-verifications/retrieve-a-business-entity-verification /spec/openapi.json get /business_entities/{business_entity}/verification # Create a business preset Source: https://docs.nmbr.co/api-reference/business-presets/create-a-business-preset /spec/openapi.json post /business_presets # Delete a business preset Source: https://docs.nmbr.co/api-reference/business-presets/delete-a-business-preset /spec/openapi.json delete /business_presets/{business_preset} # List business presets Source: https://docs.nmbr.co/api-reference/business-presets/list-business-presets /spec/openapi.json get /business_presets # Retrieve a business preset Source: https://docs.nmbr.co/api-reference/business-presets/retrieve-a-business-preset /spec/openapi.json get /business_presets/{business_preset} # Update a business preset Source: https://docs.nmbr.co/api-reference/business-presets/update-a-business-preset /spec/openapi.json put /business_presets/{business_preset} # Explain statutory holiday pay calculation Source: https://docs.nmbr.co/api-reference/calculations/explain-statutory-holiday-pay-calculation /spec/openapi.json post /calculations/statutory_holiday_pay Explain how statutory holiday pay would be calculated for the pay stub's work assignment, optionally overriding which dates are treated as holidays and/or the statutory holiday pay configuration. With no overrides, behaves as a pure explanation of how statutory holiday pay was or will be calculated under the work assignment's current configuration. # Create a company Source: https://docs.nmbr.co/api-reference/companies/create-a-company /spec/openapi.json post /companies # Delete a company Source: https://docs.nmbr.co/api-reference/companies/delete-a-company /spec/openapi.json delete /companies/{company} All Business Entities must be in Preview mode to be allowed. # Retrieve a company Source: https://docs.nmbr.co/api-reference/companies/retrieve-a-company /spec/openapi.json get /companies/{company} # Update a company Source: https://docs.nmbr.co/api-reference/companies/update-a-company /spec/openapi.json put /companies/{company} # Batch delete contractors Source: https://docs.nmbr.co/api-reference/contractors/batch-delete-contractors /spec/openapi.json post /contractors/batch/delete # Batch upsert contractors Source: https://docs.nmbr.co/api-reference/contractors/batch-upsert-contractors /spec/openapi.json post /contractors/batch/upsert # Create a contractor Source: https://docs.nmbr.co/api-reference/contractors/create-a-contractor /spec/openapi.json post /contractors # Delete a contractor Source: https://docs.nmbr.co/api-reference/contractors/delete-a-contractor /spec/openapi.json delete /contractors/{contractor} # List contractors Source: https://docs.nmbr.co/api-reference/contractors/list-contractors /spec/openapi.json get /contractors # Retrieve a contractor Source: https://docs.nmbr.co/api-reference/contractors/retrieve-a-contractor /spec/openapi.json get /contractors/{contractor} # Update a contractor Source: https://docs.nmbr.co/api-reference/contractors/update-a-contractor /spec/openapi.json put /contractors/{contractor} # Batch delete deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/batch-delete-deduction-line-items /spec/openapi.json post /deduction_line_items/batch/delete # Batch upsert deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/batch-upsert-deduction-line-items /spec/openapi.json post /deduction_line_items/batch/upsert # Bulk create deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/bulk-create-deduction-line-items /spec/openapi.json post /deduction_line_items/bulk/create # Bulk delete deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/bulk-delete-deduction-line-items /spec/openapi.json post /deduction_line_items/bulk/delete # Bulk update deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/bulk-update-deduction-line-items /spec/openapi.json post /deduction_line_items/bulk/update # Create a deduction line item Source: https://docs.nmbr.co/api-reference/deduction-line-items/create-a-deduction-line-item /spec/openapi.json post /deduction_line_items # Delete a deduction line item Source: https://docs.nmbr.co/api-reference/deduction-line-items/delete-a-deduction-line-item /spec/openapi.json delete /deduction_line_items/{deduction_line_item} # List deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/list-deduction-line-items /spec/openapi.json get /deduction_line_items # Retrieve a deduction line item Source: https://docs.nmbr.co/api-reference/deduction-line-items/retrieve-a-deduction-line-item /spec/openapi.json get /deduction_line_items/{deduction_line_item} # Search deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/search-deduction-line-items /spec/openapi.json post /deduction_line_items/search Search line items under the given payroll, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/show-bulk-create-scope-for-deduction-line-items /spec/openapi.json post /deduction_line_items/bulk/create/scope # Show bulk delete scope for deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/show-bulk-delete-scope-for-deduction-line-items /spec/openapi.json post /deduction_line_items/bulk/delete/scope # Show bulk update scope for deduction line items Source: https://docs.nmbr.co/api-reference/deduction-line-items/show-bulk-update-scope-for-deduction-line-items /spec/openapi.json post /deduction_line_items/bulk/update/scope # Update a deduction line item Source: https://docs.nmbr.co/api-reference/deduction-line-items/update-a-deduction-line-item /spec/openapi.json put /deduction_line_items/{deduction_line_item} # List deduction types Source: https://docs.nmbr.co/api-reference/deduction-types/list-deduction-types /spec/openapi.json get /deduction_types # Batch delete deductions Source: https://docs.nmbr.co/api-reference/deductions/batch-delete-deductions /spec/openapi.json post /deductions/batch/delete # Batch upsert deductions Source: https://docs.nmbr.co/api-reference/deductions/batch-upsert-deductions /spec/openapi.json post /deductions/batch/upsert # Bulk create deductions Source: https://docs.nmbr.co/api-reference/deductions/bulk-create-deductions /spec/openapi.json post /deductions/bulk/create # Bulk delete deductions Source: https://docs.nmbr.co/api-reference/deductions/bulk-delete-deductions /spec/openapi.json post /deductions/bulk/delete # Bulk update deductions Source: https://docs.nmbr.co/api-reference/deductions/bulk-update-deductions /spec/openapi.json post /deductions/bulk/update # Create a deduction Source: https://docs.nmbr.co/api-reference/deductions/create-a-deduction /spec/openapi.json post /deductions # Delete a deduction Source: https://docs.nmbr.co/api-reference/deductions/delete-a-deduction /spec/openapi.json delete /deductions/{deduction} # List deductions Source: https://docs.nmbr.co/api-reference/deductions/list-deductions /spec/openapi.json get /deductions # Retrieve a deduction Source: https://docs.nmbr.co/api-reference/deductions/retrieve-a-deduction /spec/openapi.json get /deductions/{deduction} # Search deductions Source: https://docs.nmbr.co/api-reference/deductions/search-deductions /spec/openapi.json post /deductions/search Search deductions under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for deductions Source: https://docs.nmbr.co/api-reference/deductions/show-bulk-create-scope-for-deductions /spec/openapi.json post /deductions/bulk/create/scope # Show bulk delete scope for deductions Source: https://docs.nmbr.co/api-reference/deductions/show-bulk-delete-scope-for-deductions /spec/openapi.json post /deductions/bulk/delete/scope # Show bulk update scope for deductions Source: https://docs.nmbr.co/api-reference/deductions/show-bulk-update-scope-for-deductions /spec/openapi.json post /deductions/bulk/update/scope # Update a deduction Source: https://docs.nmbr.co/api-reference/deductions/update-a-deduction /spec/openapi.json put /deductions/{deduction} # Batch delete earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/batch-delete-earning-line-items /spec/openapi.json post /earning_line_items/batch/delete # Batch upsert earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/batch-upsert-earning-line-items /spec/openapi.json post /earning_line_items/batch/upsert # Bulk create earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/bulk-create-earning-line-items /spec/openapi.json post /earning_line_items/bulk/create # Bulk delete earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/bulk-delete-earning-line-items /spec/openapi.json post /earning_line_items/bulk/delete # Bulk update earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/bulk-update-earning-line-items /spec/openapi.json post /earning_line_items/bulk/update # Create an earning line item Source: https://docs.nmbr.co/api-reference/earning-line-items/create-an-earning-line-item /spec/openapi.json post /earning_line_items # Delete an earning line item Source: https://docs.nmbr.co/api-reference/earning-line-items/delete-an-earning-line-item /spec/openapi.json delete /earning_line_items/{earning_line_item} # List earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/list-earning-line-items /spec/openapi.json get /earning_line_items # Retrieve an earning line item Source: https://docs.nmbr.co/api-reference/earning-line-items/retrieve-an-earning-line-item /spec/openapi.json get /earning_line_items/{earning_line_item} # Search earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/search-earning-line-items /spec/openapi.json post /earning_line_items/search Search line items under the given payroll, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/show-bulk-create-scope-for-earning-line-items /spec/openapi.json post /earning_line_items/bulk/create/scope # Show bulk delete scope for earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/show-bulk-delete-scope-for-earning-line-items /spec/openapi.json post /earning_line_items/bulk/delete/scope # Show bulk update scope for earning line items Source: https://docs.nmbr.co/api-reference/earning-line-items/show-bulk-update-scope-for-earning-line-items /spec/openapi.json post /earning_line_items/bulk/update/scope # Update an earning line item Source: https://docs.nmbr.co/api-reference/earning-line-items/update-an-earning-line-item /spec/openapi.json put /earning_line_items/{earning_line_item} Earning Line Items on non-draft Pay Stubs will not be able to update attributes. Any Earning Line Item with `is_managed` set to `true` will only be able to update `custom_amount` and `custom_hours` # List earning types Source: https://docs.nmbr.co/api-reference/earning-types/list-earning-types /spec/openapi.json get /earning_types # Batch delete earnings Source: https://docs.nmbr.co/api-reference/earnings/batch-delete-earnings /spec/openapi.json post /earnings/batch/delete # Batch upsert earnings Source: https://docs.nmbr.co/api-reference/earnings/batch-upsert-earnings /spec/openapi.json post /earnings/batch/upsert # Bulk create earnings Source: https://docs.nmbr.co/api-reference/earnings/bulk-create-earnings /spec/openapi.json post /earnings/bulk/create # Bulk delete earnings Source: https://docs.nmbr.co/api-reference/earnings/bulk-delete-earnings /spec/openapi.json post /earnings/bulk/delete # Bulk update earnings Source: https://docs.nmbr.co/api-reference/earnings/bulk-update-earnings /spec/openapi.json post /earnings/bulk/update # Create an earning Source: https://docs.nmbr.co/api-reference/earnings/create-an-earning /spec/openapi.json post /earnings # Delete an earning Source: https://docs.nmbr.co/api-reference/earnings/delete-an-earning /spec/openapi.json delete /earnings/{earning} # List earnings Source: https://docs.nmbr.co/api-reference/earnings/list-earnings /spec/openapi.json get /earnings # Retrieve an earning Source: https://docs.nmbr.co/api-reference/earnings/retrieve-an-earning /spec/openapi.json get /earnings/{earning} # Search earnings Source: https://docs.nmbr.co/api-reference/earnings/search-earnings /spec/openapi.json post /earnings/search Search earnings under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for earnings Source: https://docs.nmbr.co/api-reference/earnings/show-bulk-create-scope-for-earnings /spec/openapi.json post /earnings/bulk/create/scope # Show bulk delete scope for earnings Source: https://docs.nmbr.co/api-reference/earnings/show-bulk-delete-scope-for-earnings /spec/openapi.json post /earnings/bulk/delete/scope # Show bulk update scope for earnings Source: https://docs.nmbr.co/api-reference/earnings/show-bulk-update-scope-for-earnings /spec/openapi.json post /earnings/bulk/update/scope # Update an earning Source: https://docs.nmbr.co/api-reference/earnings/update-an-earning /spec/openapi.json put /earnings/{earning} # List effective tax properties Source: https://docs.nmbr.co/api-reference/effective-tax-properties/list-effective-tax-properties /spec/openapi.json get /effective_tax_properties # Batch delete employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/batch-delete-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/batch/delete # Batch upsert employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/batch-upsert-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/batch/upsert # Bulk create employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/bulk-create-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/bulk/create # Bulk delete employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/bulk-delete-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/bulk/delete # Bulk update employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/bulk-update-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/bulk/update # Create an employee benefit line item Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/create-an-employee-benefit-line-item /spec/openapi.json post /employee_benefit_line_items # Delete an employee benefit line item Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/delete-an-employee-benefit-line-item /spec/openapi.json delete /employee_benefit_line_items/{employee_benefit_line_item} # List employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/list-employee-benefit-line-items /spec/openapi.json get /employee_benefit_line_items # Retrieve an employee benefit line item Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/retrieve-an-employee-benefit-line-item /spec/openapi.json get /employee_benefit_line_items/{employee_benefit_line_item} # Search employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/search-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/search Search line items under the given payroll, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/show-bulk-create-scope-for-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/bulk/create/scope # Show bulk delete scope for employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/show-bulk-delete-scope-for-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/bulk/delete/scope # Show bulk update scope for employee benefit line items Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/show-bulk-update-scope-for-employee-benefit-line-items /spec/openapi.json post /employee_benefit_line_items/bulk/update/scope # Update an employee benefit line item Source: https://docs.nmbr.co/api-reference/employee-benefit-line-items/update-an-employee-benefit-line-item /spec/openapi.json put /employee_benefit_line_items/{employee_benefit_line_item} # List employee benefit types Source: https://docs.nmbr.co/api-reference/employee-benefit-types/list-employee-benefit-types /spec/openapi.json get /employee_benefit_types # Batch delete employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/batch-delete-employee-benefits /spec/openapi.json post /employee_benefits/batch/delete # Batch upsert employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/batch-upsert-employee-benefits /spec/openapi.json post /employee_benefits/batch/upsert # Bulk create employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/bulk-create-employee-benefits /spec/openapi.json post /employee_benefits/bulk/create # Bulk delete employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/bulk-delete-employee-benefits /spec/openapi.json post /employee_benefits/bulk/delete # Bulk update employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/bulk-update-employee-benefits /spec/openapi.json post /employee_benefits/bulk/update # Create an employee benefit Source: https://docs.nmbr.co/api-reference/employee-benefits/create-an-employee-benefit /spec/openapi.json post /employee_benefits # Delete an employee benefit Source: https://docs.nmbr.co/api-reference/employee-benefits/delete-an-employee-benefit /spec/openapi.json delete /employee_benefits/{employee_benefit} # List employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/list-employee-benefits /spec/openapi.json get /employee_benefits # Retrieve an employee benefit Source: https://docs.nmbr.co/api-reference/employee-benefits/retrieve-an-employee-benefit /spec/openapi.json get /employee_benefits/{employee_benefit} # Search employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/search-employee-benefits /spec/openapi.json post /employee_benefits/search Search benefits under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/show-bulk-create-scope-for-employee-benefits /spec/openapi.json post /employee_benefits/bulk/create/scope # Show bulk delete scope for employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/show-bulk-delete-scope-for-employee-benefits /spec/openapi.json post /employee_benefits/bulk/delete/scope # Show bulk update scope for employee benefits Source: https://docs.nmbr.co/api-reference/employee-benefits/show-bulk-update-scope-for-employee-benefits /spec/openapi.json post /employee_benefits/bulk/update/scope # Update an employee benefit Source: https://docs.nmbr.co/api-reference/employee-benefits/update-an-employee-benefit /spec/openapi.json put /employee_benefits/{employee_benefit} # Batch delete employees Source: https://docs.nmbr.co/api-reference/employees/batch-delete-employees /spec/openapi.json post /employees/batch/delete # Batch upsert employees Source: https://docs.nmbr.co/api-reference/employees/batch-upsert-employees /spec/openapi.json post /employees/batch/upsert # Create an employee Source: https://docs.nmbr.co/api-reference/employees/create-an-employee /spec/openapi.json post /employees # Delete an employee Source: https://docs.nmbr.co/api-reference/employees/delete-an-employee /spec/openapi.json delete /employees/{employee} # List employees Source: https://docs.nmbr.co/api-reference/employees/list-employees /spec/openapi.json get /employees # Retrieve an employee Source: https://docs.nmbr.co/api-reference/employees/retrieve-an-employee /spec/openapi.json get /employees/{employee} # Reveal employee SIN Source: https://docs.nmbr.co/api-reference/employees/reveal-employee-sin /spec/openapi.json get /employees/{employee}/reveal # Update an employee Source: https://docs.nmbr.co/api-reference/employees/update-an-employee /spec/openapi.json put /employees/{employee} # Batch delete employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/batch-delete-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/batch/delete # Batch upsert employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/batch-upsert-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/batch/upsert # Bulk create employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/bulk-create-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/bulk/create # Bulk delete employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/bulk-delete-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/bulk/delete # Bulk update employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/bulk-update-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/bulk/update # Create an employer benefit line item Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/create-an-employer-benefit-line-item /spec/openapi.json post /employer_benefit_line_items # Delete an employer benefit line item Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/delete-an-employer-benefit-line-item /spec/openapi.json delete /employer_benefit_line_items/{employer_benefit_line_item} # List employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/list-employer-benefit-line-items /spec/openapi.json get /employer_benefit_line_items # Retrieve an employer benefit line item Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/retrieve-an-employer-benefit-line-item /spec/openapi.json get /employer_benefit_line_items/{employer_benefit_line_item} # Search employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/search-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/search Search line items under the given payroll, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/show-bulk-create-scope-for-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/bulk/create/scope # Show bulk delete scope for employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/show-bulk-delete-scope-for-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/bulk/delete/scope # Show bulk update scope for employer benefit line items Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/show-bulk-update-scope-for-employer-benefit-line-items /spec/openapi.json post /employer_benefit_line_items/bulk/update/scope # Update an employer benefit line item Source: https://docs.nmbr.co/api-reference/employer-benefit-line-items/update-an-employer-benefit-line-item /spec/openapi.json put /employer_benefit_line_items/{employer_benefit_line_item} # List employer benefit types Source: https://docs.nmbr.co/api-reference/employer-benefit-types/list-employer-benefit-types /spec/openapi.json get /employer_benefit_types # Batch delete employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/batch-delete-employer-benefits /spec/openapi.json post /employer_benefits/batch/delete # Batch upsert employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/batch-upsert-employer-benefits /spec/openapi.json post /employer_benefits/batch/upsert # Bulk create employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/bulk-create-employer-benefits /spec/openapi.json post /employer_benefits/bulk/create # Bulk delete employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/bulk-delete-employer-benefits /spec/openapi.json post /employer_benefits/bulk/delete # Bulk update employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/bulk-update-employer-benefits /spec/openapi.json post /employer_benefits/bulk/update # Create an employer benefit Source: https://docs.nmbr.co/api-reference/employer-benefits/create-an-employer-benefit /spec/openapi.json post /employer_benefits # Delete an employer benefit Source: https://docs.nmbr.co/api-reference/employer-benefits/delete-an-employer-benefit /spec/openapi.json delete /employer_benefits/{employer_benefit} # List employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/list-employer-benefits /spec/openapi.json get /employer_benefits # Retrieve an employer benefit Source: https://docs.nmbr.co/api-reference/employer-benefits/retrieve-an-employer-benefit /spec/openapi.json get /employer_benefits/{employer_benefit} # Search employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/search-employer-benefits /spec/openapi.json post /employer_benefits/search Search benefits under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/show-bulk-create-scope-for-employer-benefits /spec/openapi.json post /employer_benefits/bulk/create/scope # Show bulk delete scope for employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/show-bulk-delete-scope-for-employer-benefits /spec/openapi.json post /employer_benefits/bulk/delete/scope # Show bulk update scope for employer benefits Source: https://docs.nmbr.co/api-reference/employer-benefits/show-bulk-update-scope-for-employer-benefits /spec/openapi.json post /employer_benefits/bulk/update/scope # Update an employer benefit Source: https://docs.nmbr.co/api-reference/employer-benefits/update-an-employer-benefit /spec/openapi.json put /employer_benefits/{employer_benefit} # Create an employer statutory withholding line item Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-line-items/create-an-employer-statutory-withholding-line-item /spec/openapi.json post /employer_statutory_withholding_line_items Only available on correction and historical payrolls. # Delete an employer statutory withholding line item Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-line-items/delete-an-employer-statutory-withholding-line-item /spec/openapi.json delete /employer_statutory_withholding_line_items/{line_item} # List employer statutory withholding line items Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-line-items/list-employer-statutory-withholding-line-items /spec/openapi.json get /employer_statutory_withholding_line_items # Retrieve an employer statutory withholding line item Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-line-items/retrieve-an-employer-statutory-withholding-line-item /spec/openapi.json get /employer_statutory_withholding_line_items/{line_item} # Update an employer statutory withholding line item Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-line-items/update-an-employer-statutory-withholding-line-item /spec/openapi.json put /employer_statutory_withholding_line_items/{line_item} Only available on correction and historical payrolls. # List employer statutory withholding types Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-types/list-employer-statutory-withholding-types /spec/openapi.json get /employer_statutory_withholding_types # Retrieve an employer statutory withholding type Source: https://docs.nmbr.co/api-reference/employer-statutory-withholding-types/retrieve-an-employer-statutory-withholding-type /spec/openapi.json get /employer_statutory_withholding_types/{withholding_type} # Create a form batch Source: https://docs.nmbr.co/api-reference/form-batches/create-a-form-batch /spec/openapi.json post /form_batches # Delete a form batch Source: https://docs.nmbr.co/api-reference/form-batches/delete-a-form-batch /spec/openapi.json delete /form_batches/{form_batch} # Download a form batch Source: https://docs.nmbr.co/api-reference/form-batches/download-a-form-batch /spec/openapi.json get /form_batches/{form_batch}/download # List form batches Source: https://docs.nmbr.co/api-reference/form-batches/list-form-batches /spec/openapi.json get /form_batches # Retrieve a form batch Source: https://docs.nmbr.co/api-reference/form-batches/retrieve-a-form-batch /spec/openapi.json get /form_batches/{form_batch} # Submit a form batch Source: https://docs.nmbr.co/api-reference/form-batches/submit-a-form-batch /spec/openapi.json post /form_batches/{form_batch}/submit Endpoint to submit a Form Batch. The following example is for a T4, but the same flow will work for any submittable form batch. # Update a form batch Source: https://docs.nmbr.co/api-reference/form-batches/update-a-form-batch /spec/openapi.json put /form_batches/{form_batch} # Generate forms Source: https://docs.nmbr.co/api-reference/form-types/generate-forms /spec/openapi.json post /form_types/{form_type}/generate Endpoint to generate forms with the values suggested by Nmbr. This is only possible for forms that support generation (T4/T4A/RL-1). This example uses a T4 form, but the same applies to other forms. # List form types Source: https://docs.nmbr.co/api-reference/form-types/list-form-types /spec/openapi.json get /form_types # Populate a form Source: https://docs.nmbr.co/api-reference/form-types/populate-a-form /spec/openapi.json post /form_types/{form_type}/populate Endpoint to populate form fields with the values suggested by Nmbr. This is only possible for forms that support population. This example uses an ROE form, but the same applies to other forms. # Retrieve a form type Source: https://docs.nmbr.co/api-reference/form-types/retrieve-a-form-type /spec/openapi.json get /form_types/{form_type} Endpoint to fetch the structure of a Form. The following example is for a 2026 TD1, but the response `fields` will differ depending on the specific Form instance requested. # Validate a form Source: https://docs.nmbr.co/api-reference/form-types/validate-a-form /spec/openapi.json post /form_types/{form_type}/validate Endpoint to validate form fields. The following example is for a 2026 TD1, but the response `fields` will differ depending on the specific Form instance requested. # Amend a form Source: https://docs.nmbr.co/api-reference/forms/amend-a-form /spec/openapi.json post /forms/{form}/amend Endpoint to amend a Form. The following example is for a T4, but the same flow will work for any amendable form. # Approve a form Source: https://docs.nmbr.co/api-reference/forms/approve-a-form /spec/openapi.json post /forms/{form}/approve Endpoint to approve a Form. The following example is for a T4, but the same flow will work for any submittable form. # Batch delete forms Source: https://docs.nmbr.co/api-reference/forms/batch-delete-forms /spec/openapi.json post /forms/batch/delete # Create a form Source: https://docs.nmbr.co/api-reference/forms/create-a-form /spec/openapi.json post /forms Endpoint to create a Form. The following example is for a 2026 TD1, but the response fields will differ depending on the specific Form instance requested. # Delete a form Source: https://docs.nmbr.co/api-reference/forms/delete-a-form /spec/openapi.json delete /forms/{form} # List forms Source: https://docs.nmbr.co/api-reference/forms/list-forms /spec/openapi.json get /forms # Retrieve a form Source: https://docs.nmbr.co/api-reference/forms/retrieve-a-form /spec/openapi.json get /forms/{form} Endpoint to fetch a Form. The following example is for a 2026 TD1, but the response fields will differ depending on the specific Form instance requested. # Submit a form Source: https://docs.nmbr.co/api-reference/forms/submit-a-form /spec/openapi.json post /forms/{form}/submit Endpoint to submit a Form. The following example is for an ROE, but the same flow will work for any submittable form. # Update a form Source: https://docs.nmbr.co/api-reference/forms/update-a-form /spec/openapi.json put /forms/{form} Endpoint to update a Form. The following example is for a 2026 TD1, but the response fields will differ depending on the specific Form instance requested. # List holidays Source: https://docs.nmbr.co/api-reference/holidays/list-holidays /spec/openapi.json get /holidays # Retrieve a holiday Source: https://docs.nmbr.co/api-reference/holidays/retrieve-a-holiday /spec/openapi.json get /holidays/{holiday} # Authenticate integration Source: https://docs.nmbr.co/api-reference/integrations/authenticate-integration /spec/openapi.json post /integrations/{integration}/authenticate # Delete an integration Source: https://docs.nmbr.co/api-reference/integrations/delete-an-integration /spec/openapi.json delete /integrations/{integration} Deactivate the integration for a business entity. # Import a partner-supplied OAuth connection Source: https://docs.nmbr.co/api-reference/integrations/import-a-partner-supplied-oauth-connection /spec/openapi.json post /integrations/{integration}/connection Register a QuickBooks or Xero connection using OAuth tokens the partner obtained directly from the provider. Pair with the partner integration credentials configured by support. # List integration tracking dimension values Source: https://docs.nmbr.co/api-reference/integrations/list-integration-tracking-dimension-values /spec/openapi.json get /integrations/{integration}/tracking_dimensions/{dimension} List the values inside a single tracking-dimension group, fetched from the connected QuickBooks or Xero account. # List integration tracking dimensions Source: https://docs.nmbr.co/api-reference/integrations/list-integration-tracking-dimensions /spec/openapi.json get /integrations/{integration}/tracking_dimensions List the tracking-dimension groups a connected QuickBooks or Xero account exposes, fetched live from the provider. # List integrations Source: https://docs.nmbr.co/api-reference/integrations/list-integrations /spec/openapi.json get /integrations # Retrieve an integration Source: https://docs.nmbr.co/api-reference/integrations/retrieve-an-integration /spec/openapi.json get /integrations/{integration} # Sync integration Source: https://docs.nmbr.co/api-reference/integrations/sync-integration /spec/openapi.json post /integrations/{integration}/sync # List journal entries Source: https://docs.nmbr.co/api-reference/journal-entries/list-journal-entries /spec/openapi.json get /journal_entries # Retrieve a journal entry Source: https://docs.nmbr.co/api-reference/journal-entries/retrieve-a-journal-entry /spec/openapi.json get /journal_entries/{journal_entry} # Batch delete overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/batch-delete-overtime-rates /spec/openapi.json post /overtime_rates/batch/delete # Batch upsert overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/batch-upsert-overtime-rates /spec/openapi.json post /overtime_rates/batch/upsert # Bulk create overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/bulk-create-overtime-rates /spec/openapi.json post /overtime_rates/bulk/create # Bulk delete overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/bulk-delete-overtime-rates /spec/openapi.json post /overtime_rates/bulk/delete # Bulk update overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/bulk-update-overtime-rates /spec/openapi.json post /overtime_rates/bulk/update # Create an overtime rate Source: https://docs.nmbr.co/api-reference/overtime-rates/create-an-overtime-rate /spec/openapi.json post /overtime_rates # Delete an overtime rate Source: https://docs.nmbr.co/api-reference/overtime-rates/delete-an-overtime-rate /spec/openapi.json delete /overtime_rates/{overtime_rate} # List overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/list-overtime-rates /spec/openapi.json get /overtime_rates # Retrieve an overtime rate Source: https://docs.nmbr.co/api-reference/overtime-rates/retrieve-an-overtime-rate /spec/openapi.json get /overtime_rates/{overtime_rate} # Search overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/search-overtime-rates /spec/openapi.json post /overtime_rates/search Search overtime rates under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/show-bulk-create-scope-for-overtime-rates /spec/openapi.json post /overtime_rates/bulk/create/scope # Show bulk delete scope for overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/show-bulk-delete-scope-for-overtime-rates /spec/openapi.json post /overtime_rates/bulk/delete/scope # Show bulk update scope for overtime rates Source: https://docs.nmbr.co/api-reference/overtime-rates/show-bulk-update-scope-for-overtime-rates /spec/openapi.json post /overtime_rates/bulk/update/scope # Update an overtime rate Source: https://docs.nmbr.co/api-reference/overtime-rates/update-an-overtime-rate /spec/openapi.json put /overtime_rates/{overtime_rate} # Retrieve a partner Source: https://docs.nmbr.co/api-reference/partners/retrieve-a-partner /spec/openapi.json get /partner # Batch delete pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/batch-delete-pay-rates /spec/openapi.json post /pay_rates/batch/delete # Batch upsert pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/batch-upsert-pay-rates /spec/openapi.json post /pay_rates/batch/upsert # Bulk create pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/bulk-create-pay-rates /spec/openapi.json post /pay_rates/bulk/create # Bulk delete pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/bulk-delete-pay-rates /spec/openapi.json post /pay_rates/bulk/delete # Bulk update pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/bulk-update-pay-rates /spec/openapi.json post /pay_rates/bulk/update # Create a pay rate Source: https://docs.nmbr.co/api-reference/pay-rates/create-a-pay-rate /spec/openapi.json post /pay_rates # Delete a pay rate Source: https://docs.nmbr.co/api-reference/pay-rates/delete-a-pay-rate /spec/openapi.json delete /pay_rates/{pay_rate} # List pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/list-pay-rates /spec/openapi.json get /pay_rates # Retrieve a pay rate Source: https://docs.nmbr.co/api-reference/pay-rates/retrieve-a-pay-rate /spec/openapi.json get /pay_rates/{pay_rate} # Search pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/search-pay-rates /spec/openapi.json post /pay_rates/search Search pay rates under the given business entity. Returns the same set the equivalent bulk update/delete operation would target with this body. Useful for previewing the blast radius of a bulk operation, or for any general search using the same criteria grammar. # Show bulk create scope for pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/show-bulk-create-scope-for-pay-rates /spec/openapi.json post /pay_rates/bulk/create/scope # Show bulk delete scope for pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/show-bulk-delete-scope-for-pay-rates /spec/openapi.json post /pay_rates/bulk/delete/scope # Show bulk update scope for pay rates Source: https://docs.nmbr.co/api-reference/pay-rates/show-bulk-update-scope-for-pay-rates /spec/openapi.json post /pay_rates/bulk/update/scope # Update a pay rate Source: https://docs.nmbr.co/api-reference/pay-rates/update-a-pay-rate /spec/openapi.json put /pay_rates/{pay_rate} # Create a pay schedule Source: https://docs.nmbr.co/api-reference/pay-schedules/create-a-pay-schedule /spec/openapi.json post /pay_schedules # Delete a pay schedule Source: https://docs.nmbr.co/api-reference/pay-schedules/delete-a-pay-schedule /spec/openapi.json delete /pay_schedules/{pay_schedule} # List pay schedules Source: https://docs.nmbr.co/api-reference/pay-schedules/list-pay-schedules /spec/openapi.json get /pay_schedules # Retrieve a pay schedule Source: https://docs.nmbr.co/api-reference/pay-schedules/retrieve-a-pay-schedule /spec/openapi.json get /pay_schedules/{pay_schedule} # Update a pay schedule Source: https://docs.nmbr.co/api-reference/pay-schedules/update-a-pay-schedule /spec/openapi.json put /pay_schedules/{pay_schedule} Pay-Schedules with non-draft Payrolls (e.g `approved` or `paid`) may only have their `title` and `title_translations` fields updated. # Create a pay split Source: https://docs.nmbr.co/api-reference/pay-splits/create-a-pay-split /spec/openapi.json post /pay_splits # Delete a pay split Source: https://docs.nmbr.co/api-reference/pay-splits/delete-a-pay-split /spec/openapi.json delete /pay_splits/{pay_split} # List pay splits Source: https://docs.nmbr.co/api-reference/pay-splits/list-pay-splits /spec/openapi.json get /pay_splits # Retrieve a pay split Source: https://docs.nmbr.co/api-reference/pay-splits/retrieve-a-pay-split /spec/openapi.json get /pay_splits/{pay_split} # Update a pay split Source: https://docs.nmbr.co/api-reference/pay-splits/update-a-pay-split /spec/openapi.json put /pay_splits/{pay_split} # Create a pay stub Source: https://docs.nmbr.co/api-reference/pay-stubs/create-a-pay-stub /spec/openapi.json post /pay_stubs # Delete a pay stub Source: https://docs.nmbr.co/api-reference/pay-stubs/delete-a-pay-stub /spec/openapi.json delete /pay_stubs/{pay_stub} # List pay stubs Source: https://docs.nmbr.co/api-reference/pay-stubs/list-pay-stubs /spec/openapi.json get /pay_stubs Pay Stubs are sorted by the employees `last_name`, and contractors `business_name`, by default. # Render a PDF pay stub Source: https://docs.nmbr.co/api-reference/pay-stubs/render-a-pdf-pay-stub /spec/openapi.json get /pay_stubs/{pay_stub}/render # Retrieve a pay stub Source: https://docs.nmbr.co/api-reference/pay-stubs/retrieve-a-pay-stub /spec/openapi.json get /pay_stubs/{pay_stub} # Search pay stubs Source: https://docs.nmbr.co/api-reference/pay-stubs/search-pay-stubs /spec/openapi.json post /pay_stubs/search Search pay stubs under the given payroll, returning the same set the equivalent bulk line item operation would target with this body. Useful for previewing the blast radius of a bulk operation, or for any general search using the same criteria grammar. # Update a pay stub Source: https://docs.nmbr.co/api-reference/pay-stubs/update-a-pay-stub /spec/openapi.json put /pay_stubs/{pay_stub} # Hold a payment Source: https://docs.nmbr.co/api-reference/payments/hold-a-payment /spec/openapi.json post /payments/{payment}/hold Place a payment on hold. Any payment can be held regardless of its status or destination. What the hold means depends on timing: holding a payment before it has been processed prevents it from being submitted to the banking network. Holding a funding payment after it has settled blocks all downstream payments (employee, CRA, RQ) from being processed, but does not reverse the settled payment. # List payments Source: https://docs.nmbr.co/api-reference/payments/list-payments /spec/openapi.json get /payments # Release a held payment Source: https://docs.nmbr.co/api-reference/payments/release-a-held-payment /spec/openapi.json post /payments/{payment}/release Release a previously held payment so normal processing can resume. Any held payment can be released regardless of its current status. Once released, pending payments will be submitted in the next processing window. Releasing a held funding payment unblocks downstream payments that were waiting for verification. # Retrieve a payment Source: https://docs.nmbr.co/api-reference/payments/retrieve-a-payment /spec/openapi.json get /payments/{payment} # Approve a payroll Source: https://docs.nmbr.co/api-reference/payrolls/approve-a-payroll /spec/openapi.json post /payrolls/{payroll}/approve # Batch upsert hours Source: https://docs.nmbr.co/api-reference/payrolls/batch-upsert-hours /spec/openapi.json post /payrolls/{payroll}/hours # Create a payroll Source: https://docs.nmbr.co/api-reference/payrolls/create-a-payroll /spec/openapi.json post /payrolls # Delete a payroll Source: https://docs.nmbr.co/api-reference/payrolls/delete-a-payroll /spec/openapi.json delete /payrolls/{payroll} # Generate a historical payroll import template Source: https://docs.nmbr.co/api-reference/payrolls/generate-a-historical-payroll-import-template /spec/openapi.json get /payrolls/{payroll}/import Downloads a CSV template pre-populated with employees on the pay schedule for importing historical payroll data. The payroll must be a historical or correction payroll in draft status. # Import historical payroll data from CSV Source: https://docs.nmbr.co/api-reference/payrolls/import-historical-payroll-data-from-csv /spec/openapi.json post /payrolls/{payroll}/import Imports historical or correction payroll data from a CSV file. The CSV should be generated using the template from the generate import endpoint, filled in with the appropriate values. Send the CSV as a `multipart/form-data` request with the file in a field named `import_file` (a `.csv` file). The payroll must be a historical or correction payroll in draft status. On success, the pay stub line items are populated with the imported data. On failure, the error response format depends on the `Accept` header: `text/csv` returns the original CSV with an added validation column containing inline error messages, while `application/json` returns a standard JSON validation error response. # List payrolls Source: https://docs.nmbr.co/api-reference/payrolls/list-payrolls /spec/openapi.json get /payrolls # Retrieve a payroll Source: https://docs.nmbr.co/api-reference/payrolls/retrieve-a-payroll /spec/openapi.json get /payrolls/{payroll} # Unapprove a payroll Source: https://docs.nmbr.co/api-reference/payrolls/unapprove-a-payroll /spec/openapi.json post /payrolls/{payroll}/unapprove # Update a payroll Source: https://docs.nmbr.co/api-reference/payrolls/update-a-payroll /spec/openapi.json put /payrolls/{payroll} # Batch delete reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/batch-delete-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/batch/delete # Batch upsert reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/batch-upsert-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/batch/upsert # Bulk create reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/bulk-create-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/bulk/create # Bulk delete reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/bulk-delete-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/bulk/delete # Bulk update reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/bulk-update-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/bulk/update # Create a reimbursement line item Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/create-a-reimbursement-line-item /spec/openapi.json post /reimbursement_line_items # Delete a reimbursement line item Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/delete-a-reimbursement-line-item /spec/openapi.json delete /reimbursement_line_items/{reimbursement_line_item} # List reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/list-reimbursement-line-items /spec/openapi.json get /reimbursement_line_items # Retrieve a reimbursement line item Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/retrieve-a-reimbursement-line-item /spec/openapi.json get /reimbursement_line_items/{reimbursement_line_item} # Search reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/search-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/search Search line items under the given payroll, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/show-bulk-create-scope-for-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/bulk/create/scope # Show bulk delete scope for reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/show-bulk-delete-scope-for-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/bulk/delete/scope # Show bulk update scope for reimbursement line items Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/show-bulk-update-scope-for-reimbursement-line-items /spec/openapi.json post /reimbursement_line_items/bulk/update/scope # Update a reimbursement line item Source: https://docs.nmbr.co/api-reference/reimbursement-line-items/update-a-reimbursement-line-item /spec/openapi.json put /reimbursement_line_items/{reimbursement_line_item} # List reimbursement types Source: https://docs.nmbr.co/api-reference/reimbursement-types/list-reimbursement-types /spec/openapi.json get /reimbursement_types # Batch delete reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/batch-delete-reimbursements /spec/openapi.json post /reimbursements/batch/delete # Batch upsert reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/batch-upsert-reimbursements /spec/openapi.json post /reimbursements/batch/upsert # Bulk create reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/bulk-create-reimbursements /spec/openapi.json post /reimbursements/bulk/create # Bulk delete reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/bulk-delete-reimbursements /spec/openapi.json post /reimbursements/bulk/delete # Bulk update reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/bulk-update-reimbursements /spec/openapi.json post /reimbursements/bulk/update # Create a reimbursement Source: https://docs.nmbr.co/api-reference/reimbursements/create-a-reimbursement /spec/openapi.json post /reimbursements # Delete a reimbursement Source: https://docs.nmbr.co/api-reference/reimbursements/delete-a-reimbursement /spec/openapi.json delete /reimbursements/{reimbursement} # List reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/list-reimbursements /spec/openapi.json get /reimbursements # Retrieve a reimbursement Source: https://docs.nmbr.co/api-reference/reimbursements/retrieve-a-reimbursement /spec/openapi.json get /reimbursements/{reimbursement} # Search reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/search-reimbursements /spec/openapi.json post /reimbursements/search Search reimbursements under the given business entity, returning the same set the equivalent bulk update/delete operation would target with this body. # Show bulk create scope for reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/show-bulk-create-scope-for-reimbursements /spec/openapi.json post /reimbursements/bulk/create/scope # Show bulk delete scope for reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/show-bulk-delete-scope-for-reimbursements /spec/openapi.json post /reimbursements/bulk/delete/scope # Show bulk update scope for reimbursements Source: https://docs.nmbr.co/api-reference/reimbursements/show-bulk-update-scope-for-reimbursements /spec/openapi.json post /reimbursements/bulk/update/scope # Update a reimbursement Source: https://docs.nmbr.co/api-reference/reimbursements/update-a-reimbursement /spec/openapi.json put /reimbursements/{reimbursement} # Bulk create remittance account enrollments Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/bulk-create-remittance-account-enrollments /spec/openapi.json post /remittance_account_enrollments/bulk/create # Bulk delete remittance account enrollments Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/bulk-delete-remittance-account-enrollments /spec/openapi.json post /remittance_account_enrollments/bulk/delete # Create a remittance account enrollment Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/create-a-remittance-account-enrollment /spec/openapi.json post /remittance_account_enrollments # Delete a remittance account enrollment Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/delete-a-remittance-account-enrollment /spec/openapi.json delete /remittance_account_enrollments/{remittance_account_enrollment} # List remittance account enrollments Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/list-remittance-account-enrollments /spec/openapi.json get /remittance_account_enrollments # Retrieve a remittance account enrollment Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/retrieve-a-remittance-account-enrollment /spec/openapi.json get /remittance_account_enrollments/{remittance_account_enrollment} # Show bulk create scope for remittance account enrollments Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/show-bulk-create-scope-for-remittance-account-enrollments /spec/openapi.json post /remittance_account_enrollments/bulk/create/scope # Show bulk delete scope for remittance account enrollments Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/show-bulk-delete-scope-for-remittance-account-enrollments /spec/openapi.json post /remittance_account_enrollments/bulk/delete/scope # Update a remittance account enrollment Source: https://docs.nmbr.co/api-reference/remittance-account-enrollments/update-a-remittance-account-enrollment /spec/openapi.json put /remittance_account_enrollments/{remittance_account_enrollment} # Create a remittance account Source: https://docs.nmbr.co/api-reference/remittance-accounts/create-a-remittance-account /spec/openapi.json post /remittance_accounts # Delete a remittance account Source: https://docs.nmbr.co/api-reference/remittance-accounts/delete-a-remittance-account /spec/openapi.json delete /remittance_accounts/{remittance_account} # List remittance accounts Source: https://docs.nmbr.co/api-reference/remittance-accounts/list-remittance-accounts /spec/openapi.json get /remittance_accounts # Retrieve a remittance account Source: https://docs.nmbr.co/api-reference/remittance-accounts/retrieve-a-remittance-account /spec/openapi.json get /remittance_accounts/{remittance_account} # Update a remittance account Source: https://docs.nmbr.co/api-reference/remittance-accounts/update-a-remittance-account /spec/openapi.json put /remittance_accounts/{remittance_account} # List remittance totals Source: https://docs.nmbr.co/api-reference/remittance-totals/list-remittance-totals /spec/openapi.json get /payrolls/{payroll}/remittances Totals every statutory withholding, deduction and benefit on the payroll that names a remittance destination, and returns one figure per destination β€” what the payroll owes the CRA, Revenue QuΓ©bec, each benefit provider, union, workers' compensation board and employer health tax authority. Totals are computed when you ask for them, so they are available on a draft payroll that has never been approved, and on historical, correction and off-cycle payrolls that never produce payments at all. The whole list comes back in one response β€” there are no pages. Line items that name no remittance destination are left out entirely; there is no catch-all entry for them. A payroll with nothing to remit returns an empty list. # Create CRA remittance report Source: https://docs.nmbr.co/api-reference/reports/create-cra-remittance-report /spec/openapi.json post /reports/cra-remittance When a CRA Remittance Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which remittances should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. `remittance_account_id`: Optional. Limits the report to a single CRA remittance account; other CRA accounts on the same business entity are excluded. Must be a CRA account, and when `business_entity_id` is also set it must belong to that business entity. # Create EHT report Source: https://docs.nmbr.co/api-reference/reports/create-eht-report /spec/openapi.json post /reports/employer-health-tax When a Employer Health Tax Report is created, the report content will be created asynchronously. It may then be retrieved asynchronously from the GET endpoint using an "accept: text/csv" header. # Create EI/CPP balance report Source: https://docs.nmbr.co/api-reference/reports/create-eicpp-balance-report /spec/openapi.json post /reports/ei-cpp-balance When an EI/CPP Balance Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. # Create EI/QPP/QPIP balance report Source: https://docs.nmbr.co/api-reference/reports/create-eiqppqpip-balance-report /spec/openapi.json post /reports/ei-qpp-qpip-balance When an EI/QPP/QPIP Balance Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. # Create journal entry report Source: https://docs.nmbr.co/api-reference/reports/create-journal-entry-report /spec/openapi.json post /reports/journal-entry When a Journal Entry Report is created, the report content will be created asynchronously. It may then be retrieved asynchronously from the GET endpoint using an "accept: text/csv", or "accept: application/vnd.ms-excel", header. # Create liability report Source: https://docs.nmbr.co/api-reference/reports/create-liability-report /spec/openapi.json post /reports/liability When a Liability Report is created, the report content will be created asynchronously. It may then be retrieved asynchronously from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you may pass a filters object here, which may contain: `payroll_type`: One or more valid payroll `type`, as array or comma separated values. `payroll_status`: One or more valid payroll `status`, as array or comma separated values. `pay_date_from`: Limits payrolls to only from this pay-date and after. `pay_date_to`: Limits payrolls to only from this pay-date and before. # Create payroll register report Source: https://docs.nmbr.co/api-reference/reports/create-payroll-register-report /spec/openapi.json post /reports/payroll-register When a Payroll Register Report is created, the report content will be created asynchronously. It may then be retrieved from `GET /reports/{id}/download`, or from `GET /reports/{id}` with an `Accept: text/csv` header. # Create RL1 preview report Source: https://docs.nmbr.co/api-reference/reports/create-rl1-preview-report /spec/openapi.json post /reports/rl1-preview When an RL-1 Preview Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. # Create RQ remittance report Source: https://docs.nmbr.co/api-reference/reports/create-rq-remittance-report /spec/openapi.json post /reports/rq-remittance When a RQ Remittance Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which remittances should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. `remittance_account_id`: Optional. Limits the report to a single RQ remittance account; other RQ accounts on the same business entity are excluded. Must be an RQ account, and when `business_entity_id` is also set it must belong to that business entity. # Create T4 preview report Source: https://docs.nmbr.co/api-reference/reports/create-t4-preview-report /spec/openapi.json post /reports/t4-preview When a T4 Preview Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. # Create vacation accrual report Source: https://docs.nmbr.co/api-reference/reports/create-vacation-accrual-report /spec/openapi.json post /reports/vacation-accrual When a Vacation Accrual Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you may pass a filters object here, which may contain: `pay_date_from`: Limits payrolls to only from this pay-date and after. `pay_date_to`: Limits payrolls to only from this pay-date and before. # Create WCB report Source: https://docs.nmbr.co/api-reference/reports/create-wcb-report /spec/openapi.json post /reports/workers-compensation When a Workers Compensation Board Report is created, the report content will be created asynchronously. It may then be retrieved asynchronously from the GET endpoint using an "accept: text/csv" header. # Create year-end forms report Source: https://docs.nmbr.co/api-reference/reports/create-year-end-forms-report /spec/openapi.json post /reports/year-end-forms When a Year-End Forms Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. This report has one sheet per form type: `t4`, `t4a` and `rl1`. A CSV holds a single sheet, and no sheet is a stand-in for the others, so a CSV request must name one with `?sheet=` or it returns 422. Requesting the Excel format instead returns all three sheets in one file. To filter which payrolls should be included in the report, you must pass a filters object here, which must contain: `year`: The year to generate the report for. # Create year-to-date report Source: https://docs.nmbr.co/api-reference/reports/create-year-to-date-report /spec/openapi.json post /reports/year-to-date When a Year to Date Report is created, the report content will be created asynchronously. It may then be retrieved from the GET endpoint using an "accept: text/csv" header. To filter which payrolls should be included in the report, you may pass a filters object here, which may contain: `pay_date_to`: Limits payrolls to only from this pay-date and before. # Delete a report Source: https://docs.nmbr.co/api-reference/reports/delete-a-report /spec/openapi.json delete /reports/{report} # Get reports download Source: https://docs.nmbr.co/api-reference/reports/get-reports-download /spec/openapi.json get /reports/{report}/download Stream the rendered report file using the `format` and `sheet` stored on the report at creation. `format` is required: it must be supplied on the original `POST /reports/*` request for this endpoint to return a file. For multi-sheet reports (e.g. Payroll Register), `sheet` must also be supplied on the POST when a specific sheet is wanted. Request-side hints (`Accept` header, `?sheet=` query param) are ignored here. Returns 422 when `format` was not stored on the report, and 404 when the report's results have not yet been generated. # Retrieve a report Source: https://docs.nmbr.co/api-reference/reports/retrieve-a-report /spec/openapi.json get /reports/{report} This endpoint allows you to retrieve the data associated with a specific report. Use the ULID provided when the report was originally generated to make the request. To download the report in CSV format, include the `Accept` header with the value `text/csv` in your request. Alternatively, the rendered file can be retrieved from `GET /reports/{id}/download` using the `format` and `sheet` supplied at creation. # Create a statutory withholding line item Source: https://docs.nmbr.co/api-reference/statutory-withholding-line-items/create-a-statutory-withholding-line-item /spec/openapi.json post /statutory_withholding_line_items Only available on correction and historical payrolls. # Delete a statutory withholding line item Source: https://docs.nmbr.co/api-reference/statutory-withholding-line-items/delete-a-statutory-withholding-line-item /spec/openapi.json delete /statutory_withholding_line_items/{statutory_withholding_line_item} # List statutory withholding line items Source: https://docs.nmbr.co/api-reference/statutory-withholding-line-items/list-statutory-withholding-line-items /spec/openapi.json get /statutory_withholding_line_items # Retrieve a statutory withholding line item Source: https://docs.nmbr.co/api-reference/statutory-withholding-line-items/retrieve-a-statutory-withholding-line-item /spec/openapi.json get /statutory_withholding_line_items/{statutory_withholding_line_item} # Update a statutory withholding line item Source: https://docs.nmbr.co/api-reference/statutory-withholding-line-items/update-a-statutory-withholding-line-item /spec/openapi.json put /statutory_withholding_line_items/{statutory_withholding_line_item} Only available on correction and historical payrolls. # List employee statutory withholding types Source: https://docs.nmbr.co/api-reference/statutory-withholding-types/list-employee-statutory-withholding-types /spec/openapi.json get /statutory_withholding_types # Retrieve an employee statutory withholding type Source: https://docs.nmbr.co/api-reference/statutory-withholding-types/retrieve-an-employee-statutory-withholding-type /spec/openapi.json get /statutory_withholding_types/{statutory_withholding_type} # Create a tag group Source: https://docs.nmbr.co/api-reference/tag-groups/create-a-tag-group /spec/openapi.json post /tag_groups # Delete a tag group Source: https://docs.nmbr.co/api-reference/tag-groups/delete-a-tag-group /spec/openapi.json delete /tag_groups/{tag_group} # List tag groups Source: https://docs.nmbr.co/api-reference/tag-groups/list-tag-groups /spec/openapi.json get /tag_groups # Retrieve a tag group Source: https://docs.nmbr.co/api-reference/tag-groups/retrieve-a-tag-group /spec/openapi.json get /tag_groups/{tag_group} # Update a tag group Source: https://docs.nmbr.co/api-reference/tag-groups/update-a-tag-group /spec/openapi.json put /tag_groups/{tag_group} # Create a tag Source: https://docs.nmbr.co/api-reference/tags/create-a-tag /spec/openapi.json post /tags # Delete a tag Source: https://docs.nmbr.co/api-reference/tags/delete-a-tag /spec/openapi.json delete /tags/{tag} # List tags Source: https://docs.nmbr.co/api-reference/tags/list-tags /spec/openapi.json get /tags # Retrieve a tag Source: https://docs.nmbr.co/api-reference/tags/retrieve-a-tag /spec/openapi.json get /tags/{tag} # Update a tag Source: https://docs.nmbr.co/api-reference/tags/update-a-tag /spec/openapi.json put /tags/{tag} # Batch delete tax properties Source: https://docs.nmbr.co/api-reference/tax-properties/batch-delete-tax-properties /spec/openapi.json post /tax_properties/batch/delete # Batch upsert tax properties Source: https://docs.nmbr.co/api-reference/tax-properties/batch-upsert-tax-properties /spec/openapi.json post /tax_properties/batch/upsert # Create a tax property Source: https://docs.nmbr.co/api-reference/tax-properties/create-a-tax-property /spec/openapi.json post /tax_properties # Delete a tax property Source: https://docs.nmbr.co/api-reference/tax-properties/delete-a-tax-property /spec/openapi.json delete /tax_properties/{tax_property} # List tax properties Source: https://docs.nmbr.co/api-reference/tax-properties/list-tax-properties /spec/openapi.json get /tax_properties # Retrieve a tax property Source: https://docs.nmbr.co/api-reference/tax-properties/retrieve-a-tax-property /spec/openapi.json get /tax_properties/{tax_property} # Update a tax property Source: https://docs.nmbr.co/api-reference/tax-properties/update-a-tax-property /spec/openapi.json put /tax_properties/{tax_property} # Retrieve a tax property template Source: https://docs.nmbr.co/api-reference/tax-property-templates/retrieve-a-tax-property-template /spec/openapi.json get /tax_property_templates/{tax_property_template} # Retrieve a new access token Source: https://docs.nmbr.co/api-reference/tokens/retrieve-a-new-access-token /spec/openapi.json post /token # Revoke access tokens Source: https://docs.nmbr.co/api-reference/tokens/revoke-access-tokens /spec/openapi.json delete /token # List usage records Source: https://docs.nmbr.co/api-reference/usage-records/list-usage-records /spec/openapi.json get /usage_records # Retrieve an usage record Source: https://docs.nmbr.co/api-reference/usage-records/retrieve-an-usage-record /spec/openapi.json get /usage_records/{usage_record} # List usage summaries Source: https://docs.nmbr.co/api-reference/usage-summaries/list-usage-summaries /spec/openapi.json get /usage_summaries # Retrieve an usage summary Source: https://docs.nmbr.co/api-reference/usage-summaries/retrieve-an-usage-summary /spec/openapi.json get /usage_summaries/{usage_summary} # Batch delete vacation pay settings Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/batch-delete-vacation-pay-settings /spec/openapi.json post /vacation_pay_settings/batch/delete # Batch upsert vacation pay settings Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/batch-upsert-vacation-pay-settings /spec/openapi.json post /vacation_pay_settings/batch/upsert # Create a vacation pay setting Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/create-a-vacation-pay-setting /spec/openapi.json post /vacation_pay_settings # Delete a vacation pay setting Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/delete-a-vacation-pay-setting /spec/openapi.json delete /vacation_pay_settings/{vacation_pay_setting} # List vacation pay settings Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/list-vacation-pay-settings /spec/openapi.json get /vacation_pay_settings # Retrieve a vacation pay setting Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/retrieve-a-vacation-pay-setting /spec/openapi.json get /vacation_pay_settings/{vacation_pay_setting} # Update a vacation pay setting Source: https://docs.nmbr.co/api-reference/vacation-pay-settings/update-a-vacation-pay-setting /spec/openapi.json put /vacation_pay_settings/{vacation_pay_setting} # Get an employee's vacation pay balance for a work assignment Source: https://docs.nmbr.co/api-reference/vacation-pay/get-an-employees-vacation-pay-balance-for-a-work-assignment /spec/openapi.json get /vacation_pay_balance This endpoint gets an employee's vacation pay balance for a work assignment. The balance covers a reporting period (specified using `period_start`, `period_end`, or `pay_date` filters) and includes the opening balance, amount accrued, amount paid, and closing balance for that period. If you need a detailed history of vacation pay accruals, payments, and adjustments by payroll, use the vacation pay history endpoint instead. # Get an employee's vacation pay history for a work assignment Source: https://docs.nmbr.co/api-reference/vacation-pay/get-an-employees-vacation-pay-history-for-a-work-assignment /spec/openapi.json get /vacation_pay_history This endpoint gets an employee's vacation pay history for a work assignment. The history includes one record per payroll in a reporting period (specified using `period_start`, `period_end`, or `pay_date` filters) and includes the opening balance, amount accrued, amount paid, closing balance, and any balance adjustment line items for the payroll, as well as basic payroll details. If you just need a vacation pay balance, use the vacation pay balance endpoint instead. # Create a webhook Source: https://docs.nmbr.co/api-reference/webhooks/create-a-webhook /spec/openapi.json post /webhooks # Delete a webhook Source: https://docs.nmbr.co/api-reference/webhooks/delete-a-webhook /spec/openapi.json delete /webhooks/{webhook} # List webhooks Source: https://docs.nmbr.co/api-reference/webhooks/list-webhooks /spec/openapi.json get /webhooks # Retrieve a webhook Source: https://docs.nmbr.co/api-reference/webhooks/retrieve-a-webhook /spec/openapi.json get /webhooks/{webhook} # Update a webhook Source: https://docs.nmbr.co/api-reference/webhooks/update-a-webhook /spec/openapi.json put /webhooks/{webhook} # Batch delete work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/batch-delete-work-assignments /spec/openapi.json post /work_assignments/batch/delete # Batch upsert work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/batch-upsert-work-assignments /spec/openapi.json post /work_assignments/batch/upsert # Bulk create work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/bulk-create-work-assignments /spec/openapi.json post /work_assignments/bulk/create Bulk-create work assignments for the selected payees (employees and contractors) on the target pay schedule. Payees that already have a work assignment on that pay schedule are skipped. # Bulk update work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/bulk-update-work-assignments /spec/openapi.json post /work_assignments/bulk/update Bulk-update the work assignments matching the selection criteria. Selection uses the same grammar as the work assignment search endpoint. # Create a work assignment Source: https://docs.nmbr.co/api-reference/work-assignments/create-a-work-assignment /spec/openapi.json post /work_assignments # Delete a work assignment Source: https://docs.nmbr.co/api-reference/work-assignments/delete-a-work-assignment /spec/openapi.json delete /work_assignments/{work_assignment} # List work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/list-work-assignments /spec/openapi.json get /work_assignments # Retrieve a work assignment Source: https://docs.nmbr.co/api-reference/work-assignments/retrieve-a-work-assignment /spec/openapi.json get /work_assignments/{work_assignment} # Search work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/search-work-assignments /spec/openapi.json post /work_assignments/search Search work assignments under the given business entity, returning the same set the equivalent bulk recurrence operation would target with this body. Useful for previewing the blast radius of a bulk operation, or for any general search using the same criteria grammar. # Show bulk create scope for work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/show-bulk-create-scope-for-work-assignments /spec/openapi.json post /work_assignments/bulk/create/scope # Show bulk update scope for work assignments Source: https://docs.nmbr.co/api-reference/work-assignments/show-bulk-update-scope-for-work-assignments /spec/openapi.json post /work_assignments/bulk/update/scope # Terminate a work assignment Source: https://docs.nmbr.co/api-reference/work-assignments/terminate-a-work-assignment /spec/openapi.json post /work_assignment/{work_assignment}/terminate # Update a work assignment Source: https://docs.nmbr.co/api-reference/work-assignments/update-a-work-assignment /spec/openapi.json put /work_assignments/{work_assignment} # Advanced Search Source: https://docs.nmbr.co/api/bulk-and-batch-operations/advanced-search Nmbr's API exposes a family of `POST //search` endpoints that return entities matching a structured selection-criteria payload. They are useful when you need to find or preview a set of entities β€” typically before deciding whether to perform a bulk operation on them. These endpoints are distinct from the simple `search` query parameter accepted by some `GET` list endpoints, which performs a text match against names. Advanced search endpoints accept a JSON body and support structured filters on relationships and attributes. ## Relationship to Bulk Operations Each advanced search endpoint accepts the **same selection-criteria grammar** as the corresponding [bulk update](./bulk-and-batch-operations#bulk-operations) and bulk delete endpoints, minus any bulk-only restrictions: * The payroll does not have to be in draft status. * Managed line items are included in the results. This makes advanced search useful for tooling that needs to browse or preview entities regardless of payroll state, while bulk operations apply only to entities the caller may mutate. If you want to preview which entities a specific bulk operation would affect β€” with the bulk-only restrictions applied β€” use the corresponding [scope endpoint](./bulk-and-batch-operations#scope-endpoints) instead. ## Endpoints | Endpoint | Returns | | ------------------------------------------ | ------------------------------------------- | | `POST /pay_stubs/search` | Pay stubs in a payroll | | `POST /work_assignments/search` | Work assignments in a business entity | | `POST /pay_rates/search` | Pay rates under matching work assignments | | `POST /overtime_rates/search` | Overtime rates under matching pay rates | | `POST /s/search` | Recurrences under matching work assignments | | `POST /_line_items/search` | Line items on matching pay stubs | `` is one of: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` `` is one of: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ## Request Shape The request body always identifies a parent scope and one or more criteria objects. Two parent scopes are used across the family: * **Payroll-scoped** endpoints (`pay_stubs`, line items): require `payroll_id` and accept `pay_stubs.include` / `pay_stubs.exclude`. * **Business-entity-scoped** endpoints (`work_assignments`, `pay_rates`, `overtime_rates`, recurrences): require `business_entity_id` and accept `work_assignments.include` / `work_assignments.exclude`. ### Pay Stub Criteria Used by `/pay_stubs/search` and the line item search endpoints. `pay_stubs.include` can be either the string `"all"` or an object with one of: * `ids`: array of pay stub IDs * `work_assignment_ids`: array of work assignment IDs, selecting the pay stubs for those work assignments * `payee_type`: `"employee"` or `"contractor"` `pay_stubs.exclude` is optional and accepts the same object shape (without `"all"`). ### Work Assignment Criteria Used by `/work_assignments/search`, `/pay_rates/search`, `/overtime_rates/search`, and the recurrence search endpoints. `work_assignments.include` can be either the string `"all"` or an object with one of: * `ids`: array of work assignment IDs * `payee_type`: `"employee"` or `"contractor"` * `pay_schedule_id`: ID of a pay schedule * `archived`: `true` to match archived work assignments, `false` to match active ones * `payee_names`: string matched against the payee's name `work_assignments.exclude` is optional and accepts the same object shape (without `"all"`). ### Additional Criteria Recurrence and line item search endpoints accept additional filters that narrow the matched entities under the selected parents: * `business_presets.include.ids` / `business_presets.exclude.ids`: filter by the entity's business preset. Use `null` in the array to match entities with no business preset. * `expense_accounting_codes.include.ids` / `expense_accounting_codes.exclude.ids`: filter by expense accounting code. Use `null` to match entities with no expense accounting code. * `liability_accounting_codes.include.ids` / `liability_accounting_codes.exclude.ids`: filter by liability accounting code. Use `null` to match entities with no liability accounting code. Recurrence search endpoints additionally accept: * `effective_from` / `effective_to`: filter by the recurrence's effective date range. * `subtype`: filter by the recurrence subtype (e.g. `cell_phone_allowance`, `bonus_discretionary`). * `ids`: filter to a specific set of recurrence IDs. Refer to the API reference for each endpoint for the exhaustive list of supported criteria. ## Response Each endpoint returns `200 OK` with a paginated collection of the matching entities, in the same shape as the corresponding `GET` list endpoint. ```json theme={null} { "data": [ { "id": "alw_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...entity properties... } }, ... ] } ``` On failure, the endpoint returns `422 Unprocessable Entity` with standard validation messages. ## Examples ### Find all pay stubs in a payroll `POST /pay_stubs/search` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" } } ``` ### Find work assignments by payee name `POST /work_assignments/search` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "payee_names": "Smith" } } } ``` ### Find all recurring allowances tied to a specific business preset `POST /allowances/search` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "business_presets": { "include": { "ids": ["rps_01J8KXD3M7RQWN2FXZV9Y4H6B1"] } } } ``` ### Find earning line items on contractor pay stubs `POST /earning_line_items/search` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "payee_type": "contractor" } } } ``` # Batch Operations Source: https://docs.nmbr.co/api/bulk-and-batch-operations/batch-operations ## Asynchronous Execution Batch operations are asynchronous. Every batch endpoint returns an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle that you use to track completion and retrieve the affected entities. The task **may or may not have completed** by the time you receive the response β€” `data.status` could be `processing` or `completed`. **Partners must always check `data.status` and not assume the work has finished.** You have two ways to observe completion: * **Poll** the URL in `links.self` on the response until `data.status` is `completed` (or `error`). * **Subscribe** to the [`async_task_completed`](/api/overview/webhook-structure) webhook event, which fires when the task finishes, whether it succeeded or failed. The webhook carries no status. Fetch the task to see how it ended: `data.status` is `completed` on success and `error` on failure. See [Failed Tasks](/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks) for the failure details a batch reports. ## Batch Upsert Nmbr's API allows you to create or update ("upsert") multiple entities of a single type in a single API call. ### Endpoint `POST /s/batch/upsert` `` can be one of the following types: * Recurrences * `pay_rate` * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` * Line Items * `allowance_line_item` * `deduction_line_item` * `earning_line_item` * `employee_benefit_line_item` * `employer_benefit_line_item` * `reimbursement_line_item` * Other * `employee` * `contractor` * `work_assignment` * `pay_stub` ### Request The body of the request must be an array of entity objects. These properties of the entity objects are documented in the API reference for each entity type, but in general the batch upsert endpoint takes the same properties with the same restrictions as the one-off create or update endpoints. If an object includes an `id` property, the existing entity with that ID will be updated. Otherwise, a new entity will be created. For example, this request updates one existing earning line item (with ID `ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8`) and creates two new earning line items: `POST /earning_line_items/batch/upsert` ```json theme={null} [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "custom_amount": 500.0, "custom_hours": 5 }, { "pay_stub_id": "payst_01J8KXB4N6RQWM2FVZH9Y3T5C8", "earning_type": "wage", "title": "Tuesday Wages", "custom_amount": 300.0, "custom_hours": 3 }, { "pay_stub_id": "payst_01J8KXB4N6RQWM2FVZH9Y3T5C8", "earning_type": "wage", "title": "Wednesday Wages", "custom_amount": 400.0, "custom_hours": 4 } ] ``` ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. See [Asynchronous Execution](#asynchronous-execution) for how to track completion. **⚠️ Partners must treat any 200-level response as success. ⚠️** For example, the response to the upsert request above might look like: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "batch_upsert", "status": "processing", "completed_at": null, "results": [], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:32Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` Once the task completes β€” either when you poll `links.self` and see `data.status` change, or when the [`async_task_completed`](/api/overview/webhook-structure) webhook arrives β€” `data.results` will contain one entry per request entity, in the same order. `results[n]` corresponds to `data[n]` in the request body, whether the entity was created or updated: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "batch_upsert", "status": "completed", "completed_at": "2026-05-19T16:14:35Z", "results": [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "earning_line_item" }, { "id": "ernli_01KBMZDVV9G7713DJRYP9RJFTP", "object": "earning_line_item" }, { "id": "ernli_01KBMZE2SY5HWB4WWR9Q8960K8", "object": "earning_line_item" } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. In order to identify which entity in the request the validation messages apply to, the validation message keys will be prefixed with `data.n.`, where `n` is the zero-based index of the entity. For example, if the first earning entity in a request had an invalid `business_preset_id` value, the validation message key would be `data.0.business_preset_id` ``` ... "data.0.business_preset_id": "The selected business_preset_id is invalid.", ... ``` ### Notes * If any entity fails validation, no entities will be created or updated. * When using a `business_preset_id`, properties must either be omitted or match the preset's values. * If batch upserting line items, the payroll's totals are automatically recalculated after the batch upsert. * If batch upserting line items, the payroll must be in draft status. ## Batch Delete Line Items Nmbr's API allows you to delete multiple entities of a single type in a single API call. ### Endpoint `POST /s/batch/delete` `` can be one of the following types: * Recurrences * `pay_rate` * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` * Line Items * `allowance_line_item` * `deduction_line_item` * `earning_line_item` * `employee_benefit_line_item` * `employer_benefit_line_item` * `reimbursement_line_item` * Other * `employee` * `contractor` * `work_assignment` * `pay_stub` ### Request The body of the request must be an array of the IDs of the entities to delete. For example, this request deletes three earning line items: `POST /earning_line_items/batch/delete` ```json theme={null} [ "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "ernli_01KBMZDVV9G7713DJRYP9RJFTP", "ernli_01KBMZE2SY5HWB4WWR9Q8960K8" ] ``` ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. See [Asynchronous Execution](#asynchronous-execution) for how to track completion. **⚠️ Partners must treat any 200-level response as success. ⚠️** For example, the response to the delete request above might look like: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "batch_delete", "status": "processing", "completed_at": null, "results": [], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:32Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` Once the task completes β€” either when you poll `links.self` and see `data.status` change, or when the [`async_task_completed`](/api/overview/webhook-structure) webhook arrives β€” `data.results` will contain one entry per request ID, in the same order. `results[n]` corresponds to `data[n]` in the request body. Deleted entities are still surfaced by ID β€” the records soft-delete and remain queryable: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "batch_delete", "status": "completed", "completed_at": "2026-05-19T16:14:35Z", "results": [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "earning_line_item" }, { "id": "ernli_01KBMZDVV9G7713DJRYP9RJFTP", "object": "earning_line_item" }, { "id": "ernli_01KBMZE2SY5HWB4WWR9Q8960K8", "object": "earning_line_item" } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. In order to identify which entity in the request the validation messages apply to, the validation message keys will be prefixed with `data.n.`, where `n` is the zero-based index of the entity. For example, if the first entity in a request couldn't be deleted because it was a managed line item, the validation message key would be `data.0.is_managed` ``` ... "data.0.is_managed": "The line item is managed and cannot be deleted.", ... ``` ### Notes * If any entity fails validation, no entities will be deleted. * If batch deleting line items, the line item must not be a managed line item. * If batch deleting line items, the payroll's totals are automatically recalculated after the batch delete. * If batch deleting line items, the payroll must be in draft status. # Bulk and Batch Operations Source: https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-and-batch-operations Nmbr supports a number of bulk and batch operations for managing multiple recurrences, line items, and other objects in one API call: * [Bulk Recurrence Operations](./bulk-recurrence-operations) * [Bulk Line Item Operations](./bulk-line-item-operations) * [Bulk Work Assignment Operations](./bulk-work-assignment-operations) * [Bulk Pay Stub Operations](./bulk-pay-stub-operations) * [Batch Operations](./batch-operations) The distinction between "bulk" and "batch" is subtle but important. ## Bulk Operations Bulk operations * take *criteria objects* that define the criteria used to select the objects to perform the bulk operation on, * find all objects matching the criteria, and * perform the same operation on each object. For example, the bulk operations for line items take criteria objects that define which pay stubs' line items will be affected by the operation. **Example: Enroll all work assignments in a pay schedule to a CRA remittance account** `POST /remittance_account_enrollments/bulk/create` ```json theme={null} { "business_entity_id": "", "work_assignments": { "include": { "pay_schedule_id": "" } }, "data": { "remittance_account_id": "", "effective_from": "2026-01-01", "overlap_strategy": "replace_existing" } } ``` This creates one enrollment for every work assignment selected by `work_assignments`. Setting `overlap_strategy` to `replace_existing` resolves overlapping enrollments for the same work assignment and provider: enrollments beginning before the new `effective_from` are end-dated, while those beginning on or after it are removed. Omit it and an overlap returns a validation error. **Example: Create earning line items on all non-contractor pay stubs in a payroll** `POST /earning_line_items/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all", "exclude": { "payee_type": "contractor" } }, "data": { "earning_type": "bonus_discretionary", "custom_amount": 300.0, "title": "Christmas Bonus" } } ``` **Example: Update all earning line items with a specific business preset on all pay stubs in a payroll** `POST /earning_line_items/bulk/update` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "business_presets": { "include": { "ids": ["rps_01J8KXD3M7RQWN2FXZV9Y4H6B1"] } }, "data": { "custom_amount": 500.0 } } ``` **Example: Delete all earning line items on all pay stubs in a payroll** `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" } } ``` ### Scope Endpoints Every bulk operation has a corresponding **scope** endpoint that previews which entities will be affected by the operation, without performing it. Scope endpoints accept the same request body as their corresponding bulk operation and return the entities that would be affected. The scope endpoint URL is the bulk operation URL with `/scope` appended: | Bulk Operation | Scope Endpoint | | -------------------------- | -------------------------------- | | `POST //bulk/create` | `POST //bulk/create/scope` | | `POST //bulk/update` | `POST //bulk/update/scope` | | `POST //bulk/delete` | `POST //bulk/delete/scope` | What the scope endpoint returns depends on the operation: * **Create scope** returns the *parent* entities the new entities will be created under (e.g. pay stubs for line items, work assignments for recurrences, payees for work assignments, work assignments for pay stubs). * **Update scope** returns the entities that will be updated. * **Delete scope** returns the entities that will be deleted. Work assignments don't support a bulk delete, so they have no delete scope endpoint. See [Bulk Line Item Operations](./bulk-line-item-operations), [Bulk Recurrence Operations](./bulk-recurrence-operations), [Bulk Work Assignment Operations](./bulk-work-assignment-operations), and [Bulk Pay Stub Operations](./bulk-pay-stub-operations) for details on the scope endpoints for each type. ## Batch Operations Batch operations take one object or ID for each entity to perform the batch operation on. For example, the batch upsert operations for line items take one object per line item, and will create or update each line item with that object's properties. For example, the batch delete operations for line items take one ID per line item, and will delete the line item with that ID. ## Comparing Bulk and Batch Operations Bulk operations take criteria objects and perform the operation on 0..n entities, all with the same properties. Batch operations take objects or IDs and perform the operation on each entity, 1:1, with different properties per object. ## Asynchronous Execution All bulk and batch mutating operations are asynchronous: they return `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. The task may or may not have completed by the time the response arrives β€” partners must always check `data.status` (poll `links.self`, or subscribe to the [`async_task_completed`](/api/overview/webhook-structure) webhook). See [Batch Operations](./batch-operations#asynchronous-execution), [Bulk Line Item Operations](./bulk-line-item-operations#asynchronous-execution), [Bulk Recurrence Operations](./bulk-recurrence-operations#asynchronous-execution), [Bulk Work Assignment Operations](./bulk-work-assignment-operations#asynchronous-execution), and [Bulk Pay Stub Operations](./bulk-pay-stub-operations#asynchronous-execution) for the per-section details. Scope endpoints are synchronous previews with no side effects. ### Failed Tasks The `async_task_completed` webhook fires when the task reaches its final state, whether the work succeeded or failed. It tells you the task is done, not that it worked. The payload carries no status, so fetch the task with the ID from the webhook and read `data.status`: * `completed`: the work succeeded. `completed_at` is set, and `data.results` lists the affected entities. * `error`: the work failed. `completed_at` stays `null`. A batch is atomic, so an errored batch task wrote nothing. The entities it could not write appear in `data.results` with `status` set to `error` and a message in `error`. `id` is `null` when the entity was being created: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "batch_upsert", "status": "error", "completed_at": null, "results": [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "earning_line_item", "status": "error", "error": "There was an unexpected error when updating this object." } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` An errored bulk task reports no per-entity detail: `data.results` is empty. The writes run in a single transaction, but the work that follows them (recalculating a payroll's totals, for example) does not, so re-read the entities the operation targeted to see what landed before you retry. # Bulk Line Item Operations Source: https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-line-item-operations ## Asynchronous Execution Bulk line item operations are asynchronous. Every bulk endpoint returns an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle that you use to track completion and retrieve the affected entities. The task **may or may not have completed** by the time you receive the response β€” `data.status` could be `processing` or `completed`. **Partners must always check `data.status` and not assume the work has finished.** You have two ways to observe completion: * **Poll** the URL in `links.self` on the response until `data.status` is `completed` (or `error`). * **Subscribe** to the [`async_task_completed`](/api/overview/webhook-structure) webhook event, which fires when the task finishes, whether it succeeded or failed. The webhook carries no status. Fetch the task to see how it ended: `data.status` is `completed` on success and `error` on failure. See [Failed Tasks](/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks). `data.results` contains one entry per affected line item β€” only the `id` and `object`. To retrieve full line item bodies, follow up with a [list query](/api-reference/earning-line-items/list-earning-line-items) (filtered by the returned IDs) or fetch individual entities by ID. Note: scope endpoints (`/bulk/*/scope`) are previews with no side effects and are synchronous - they return `200 OK` with the inline list of matched entities. ## Bulk Create Line Items Nmbr's API allows you to create a line item on select pay stubs within a single payroll. This endpoint is useful when you need to create line items on one or more pay stubs in one API call, such as applying a company-wide bonus to a group of employees. ### Endpoint `POST /_line_items/bulk/create` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ### Request ```json theme={null} { "payroll_id": ULID, "pay_stubs": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { ...type-specific line item properties... } } ``` #### Request Properties | Property | Type | Required | Description | | ------------------- | -------------------------- | -------- | ------------------------------------------- | | `payroll_id` | ULID | Yes | ID of the payroll containing the pay stubs | | `pay_stubs.include` | criteria object or `"all"` | Yes | Criteria for selecting pay stubs to include | | `pay_stubs.exclude` | criteria object | No | Criteria for selecting pay stubs to exclude | | `data` | object | Yes | The properties of the line item to create | The `data` object contains any line item properties specific to the type of line item being created. For example, for earning line items: | Property | Description | | ------------------------------ | --------------------------------------------------------- | | `earning_type` | Type of earning (e.g., `"wage"`, `"bonus"`, `"overtime"`) | | `business_preset_id` | ID of a business preset to use as template | | `custom_amount` | Amount for the line item | | `custom_hours` | Hours for the line item | | `title` | Title for the line item | | `expense_accounting_code_id` | ID of the expense accounting code | | `liability_accounting_code_id` | ID of the liability accounting code | These properties are documented in more detail in the API reference for each line item type. #### Request Criteria Objects `include` and `exclude` can be objects with one of the following properties: * `ids`: Array of pay stub IDs to include * `work_assignment_ids`: Array of work assignment IDs. Selects the pay stubs for those work assignments * `payee_type`: `"employee"` or `"contractor"` `include` can also be the string `"all"` to include all pay stubs. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. See [Asynchronous Execution](#asynchronous-execution) for how to track completion. **⚠️ Partners must treat any 200-level response as success. ⚠️** For example, the response might look like: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "processing", "completed_at": null, "results": [], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:32Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` Once the task completes, `data.results` will contain one entry per created line item: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "completed", "completed_at": "2026-05-19T16:14:35Z", "results": [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "earning_line_item" }, { "id": "ernli_01KBMZDVV9G7713DJRYP9RJFTP", "object": "earning_line_item" } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The same line item properties will be applied to all selected pay stubs. * When using a `business_preset_id`, properties must either be omitted or match the preset's values. * The operation only affects pay stubs within the specified payroll. Pay stubs in other payrolls will not be affected. * Invalid pay stub IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. * The payroll's totals are automatically recalculated after the bulk creation. * The payroll must be in draft status. ### Examples #### Create an earning line item on all pay stubs `POST /earning_line_items/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "data": { "earning_type": "bonus_discretionary", "custom_amount": 500.0, "title": "Year-end Bonus" } } ``` #### Create earning line items using a business preset `POST /earning_line_items/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "data": { "business_preset_id": "rps_01J8KXD3M7RQWN2FXZV9Y4H6B1", "custom_amount": 100.0 } } ``` #### Create earning line items for specific pay stubs `POST /earning_line_items/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "ids": [ "payst_01J8KXB4N6RQWM2FVZH9Y3T5C8", "payst_01J8KXB7P2MQVW4RXZN6Y8H3F1", "payst_01J8KXBA3TWQNM7FXZR9Y2V5C4" ] } }, "data": { "earning_type": "wage", "custom_amount": 1000.0, "title": "Special Assignment Pay" } } ``` #### Create earning line items on all employee pay stubs, excluding specific pay stubs (and implicitly excluding contractor pay stubs) `POST /earning_line_items/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "payee_type": "employee" }, "exclude": { "ids": ["payst_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } }, "data": { "earning_type": "bonus_discretionary", "custom_amount": 250.0, "title": "Appreciation Bonus", "expense_accounting_code_id": "accod_01J8KXF2N4MQRW3VXZH7Y9B5C8", "liability_accounting_code_id": "accod_01J8KXF5P6RQNW4MXZV8Y2H7F1" } } ``` #### Create earning line items for all pay stubs except contractors `POST /earning_line_items/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all", "exclude": { "payee_type": "contractor" } }, "data": { "earning_type": "bonus_discretionary", "custom_amount": 200.0, "title": "Christmas Bonus" } } ``` ## Bulk Create Line Items Scope The create scope endpoint previews which pay stubs will have new line items created on them by a bulk create operation. It accepts the same request body as the bulk create endpoint, but instead of creating line items, it returns the pay stubs that match the criteria. This is useful for confirming which pay stubs a bulk create will affect before executing it. ### Endpoint `POST /_line_items/bulk/create/scope` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ### Request The request body is the same as the [bulk create](#bulk-create-line-items) endpoint. ### Response On success, the operation will return `200 OK` with an array of pay stubs that the bulk create would create line items on: ```json theme={null} { "data": [ { "id": "payst_01J8KXB4N6RQWM2FVZH9Y3T5C8", "data": { ...pay stub properties... } }, ... ] } ``` ## Bulk Update Line Items Nmbr's API allows you to update all line items of a single type on select pay stubs within a single payroll. This endpoint is useful when you need to update the same property on one or more line items in one API call, such as changing the amount or accounting code on a group of line items. ### Endpoint `POST /_line_items/bulk/update` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ### Request ```json theme={null} { "payroll_id": "string", "pay_stubs": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "business_presets": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "expense_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "liability_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "data": { ...properties to update... } } ``` #### Request Properties | Property | Type | Required | Description | | ---------------------------------------- | -------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `payroll_id` | ULID | Yes | ID of the payroll containing the pay stubs | | `pay_stubs.include` | criteria object or `"all"` | Yes | Criteria for selecting pay stubs to include | | `pay_stubs.exclude` | criteria object | No | Criteria for selecting pay stubs to exclude | | `business_presets.include.ids` | array of ULIDs or `null` | No | Only update line items with one of these business preset IDs. Use `null` to match line items with no business preset. | | `business_presets.exclude.ids` | array of ULIDs or `null` | No | Exclude line items with one of these business preset IDs. Use `null` to exclude line items with no business preset. | | `expense_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only update line items with one of these expense accounting code IDs. Use `null` to match line items with no expense accounting code. | | `expense_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude line items with one of these expense accounting code IDs. Use `null` to exclude line items with no expense accounting code. | | `liability_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only update line items with one of these liability accounting code IDs. Use `null` to match line items with no liability accounting code. | | `liability_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude line items with one of these liability accounting code IDs. Use `null` to exclude line items with no liability accounting code. | | `data` | object | Yes | The properties to update on the matching line items | The `data` object contains any line item properties to update. These are the same properties accepted by the single-resource update endpoint for each line item type, and are documented in the API reference for each type. #### Pay Stub Criteria Objects `include` and `exclude` can be objects with one of the following properties: * `ids`: Array of pay stub IDs to include or exclude * `work_assignment_ids`: Array of work assignment IDs. Selects the pay stubs for those work assignments * `payee_type`: `"employee"` or `"contractor"` `include` can also be the string `"all"` to include all pay stubs. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the updated line items. See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Line Items β€Ί Response](#response) for an example response shape β€” `data.type` will be `bulk_update`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. If any line item fails per-model validation, the entire request fails and no line items are updated. ### Notes * The same update properties will be applied to all selected line items. * The operation only affects custom line items. Managed line items will not be affected. * The payroll must be in draft status. * The payroll's totals are automatically recalculated after the bulk update. * The `pay_stubs` criteria select which pay stubs to look under. The `business_presets`, `expense_accounting_codes`, and `liability_accounting_codes` criteria further filter which line items under those pay stubs are updated. ### Examples #### Update the amount on all earning line items `POST /earning_line_items/bulk/update` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "data": { "custom_amount": 500.0 } } ``` #### Update the accounting code on all earning line items with a specific business preset `POST /earning_line_items/bulk/update` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "business_presets": { "include": { "ids": ["rps_01J8KXD3M7RQWN2FXZV9Y4H6B1"] } }, "data": { "expense_accounting_code_id": "accod_01J8KXF2N4MQRW3VXZH7Y9B5C8" } } ``` #### Update earning line items that have no business preset `POST /earning_line_items/bulk/update` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "business_presets": { "include": { "ids": [null] } }, "data": { "custom_amount": 500.0 } } ``` ## Bulk Update Line Items Scope The update scope endpoint previews which line items will be updated by a bulk update operation. It accepts the same request body as the bulk update endpoint, but instead of updating line items, it returns the line items that match the criteria. ### Endpoint `POST /_line_items/bulk/update/scope` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ### Request The request body is the same as the [bulk update](#bulk-update-line-items) endpoint. ### Response On success, the operation will return `200 OK` with an array of the line items that would be updated: ```json theme={null} { "data": [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...line item properties... } }, ... ] } ``` ### Notes * Only custom line items are returned. Managed line items are excluded, matching the behavior of the bulk update operation. ## Bulk Delete Line Items Nmbr's API allows you to delete all line items of a single type on select pay stubs within a single payroll. This endpoint is useful when you need to remove line items on one or more pay stubs in one API call. **Important:** This operation deletes ALL line items of the specified type on the pay stubs, not specific line items. If you want to delete specific line items, you should use the batch delete line items endpoints instead. ### Endpoint `POST /_line_items/bulk/delete` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ### Request ```json theme={null} { "payroll_id": "string", "pay_stubs": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "business_presets": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "expense_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "liability_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } } } ``` #### Request Properties | Property | Type | Required | Description | | ---------------------------------------- | -------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `payroll_id` | ULID | Yes | ID of the payroll containing the pay stubs | | `pay_stubs.include` | criteria object or `"all"` | Yes | Criteria for selecting pay stubs to include | | `pay_stubs.exclude` | criteria object | No | Criteria for selecting pay stubs to exclude | | `business_presets.include.ids` | array of ULIDs or `null` | No | Only delete line items with one of these business preset IDs. Use `null` to match line items with no business preset. | | `business_presets.exclude.ids` | array of ULIDs or `null` | No | Exclude line items with one of these business preset IDs. Use `null` to exclude line items with no business preset. | | `expense_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only delete line items with one of these expense accounting code IDs. Use `null` to match line items with no expense accounting code. | | `expense_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude line items with one of these expense accounting code IDs. Use `null` to exclude line items with no expense accounting code. | | `liability_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only delete line items with one of these liability accounting code IDs. Use `null` to match line items with no liability accounting code. | | `liability_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude line items with one of these liability accounting code IDs. Use `null` to exclude line items with no liability accounting code. | #### Pay Stub Criteria Objects `include` and `exclude` can be objects with one of the following properties: * `ids`: Array of pay stub IDs to include or exclude * `work_assignment_ids`: Array of work assignment IDs. Selects the pay stubs for those work assignments * `payee_type`: `"employee"` or `"contractor"` `include` can also be the string `"all"` to include all pay stubs. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the deleted line items (still surfaced by ID β€” the records soft-delete and remain queryable). See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Line Items β€Ί Response](#response) for an example response shape β€” `data.type` will be `bulk_delete`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The operation only affects pay stubs within the specified payroll. Pay stubs in other payrolls will not be affected. * The operation only affects custom line items. Managed line items (e.g. earning line items created by statutory holidays or automatic vacation payouts; statutory withholding line items) will not be affected. * Invalid pay stub IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. * The payroll's totals are automatically recalculated after the bulk deletion. * The payroll must be draft. * The `pay_stubs` criteria select which pay stubs to look under. The `business_presets`, `expense_accounting_codes`, and `liability_accounting_codes` criteria further filter which line items under those pay stubs are deleted. ### Examples #### Delete all earning line items on all pay stubs in a payroll `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" } } ``` #### Delete earning line items on specific pay stubs `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "ids": [ "payst_01J8KXB4N6RQWM2FVZH9Y3T5C8", "payst_01J8KXB7P2MQVW4RXZN6Y8H3F1", "payst_01J8KXBA3TWQNM7FXZR9Y2V5C4" ] } } } ``` #### Delete earning line items for all employees, excluding specific pay stubs `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "payee_type": "employee" }, "exclude": { "ids": ["payst_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } } } ``` #### Delete earning line items for all pay stubs except contractors `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all", "exclude": { "payee_type": "contractor" } } } ``` #### Delete only earning line items with a specific business preset `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "business_presets": { "include": { "ids": ["rps_01J8KXD3M7RQWN2FXZV9Y4H6B1"] } } } ``` #### Delete earning line items that have no business preset `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "business_presets": { "include": { "ids": [null] } } } ``` #### Delete earning line items with a specific expense accounting code `POST /earning_line_items/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "expense_accounting_codes": { "include": { "ids": ["accod_01J8KXF2N4MQRW3VXZH7Y9B5C8"] } } } ``` ## Bulk Delete Line Items Scope The delete scope endpoint previews which line items will be deleted by a bulk delete operation. It accepts the same request body as the bulk delete endpoint, but instead of deleting line items, it returns the line items that match the criteria. ### Endpoint `POST /_line_items/bulk/delete/scope` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `reimbursement` ### Request The request body is the same as the [bulk delete](#bulk-delete-line-items) endpoint. ### Response On success, the operation will return `200 OK` with an array of the line items that would be deleted: ```json theme={null} { "data": [ { "id": "ernli_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...line item properties... } }, ... ] } ``` ### Notes * Only custom line items are returned. Managed line items are excluded, matching the behavior of the bulk delete operation. # Bulk Pay Stub Operations Source: https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-pay-stub-operations Bulk pay stub operations create, update, or delete many pay stubs in one API call. They apply only to payrolls that accept manual pay stub management: once-off, historical, correction, and custom-schedule payrolls in `draft` status. Regular scheduled payrolls generate their pay stubs automatically, so you can't bulk-create on them. Selection differs between create and update/delete: * **Create** selects *work assignments* on the payroll's pay schedule and creates one pay stub per work assignment. * **Update** and **delete** select *pay stubs* that already exist on the payroll. ## Asynchronous Execution Bulk pay stub operations are asynchronous. Every bulk endpoint returns an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle that you use to track completion and retrieve the affected entities. The task **may or may not have completed** by the time you receive the response. `data.status` could be `processing` or `completed`. **Partners must always check `data.status` and not assume the work has finished.** You have two ways to observe completion: * **Poll** the URL in `links.self` on the response until `data.status` is `completed` (or `error`). * **Subscribe** to the [`async_task_completed`](/api/overview/webhook-structure) webhook event, which fires when the task finishes, whether it succeeded or failed. The webhook carries no status. Fetch the task to see how it ended: `data.status` is `completed` on success and `error` on failure. See [Failed Tasks](/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks). `data.results` contains one entry per affected pay stub, with only the `id` and `object`. To retrieve full pay stub bodies, follow up with a [list query](/api-reference/pay-stubs/list-pay-stubs) (filtered by the returned IDs) or fetch individual pay stubs by ID. Note: scope endpoints (`/bulk/*/scope`) are previews with no side effects and are synchronous - they return `200 OK` with the inline list of matched entities. ## Bulk Create Pay Stubs Nmbr's API allows you to create a pay stub for select work assignments on a single payroll. This endpoint is useful when you need to add a group of employees or contractors to an off-cycle or historical payroll in one API call. Create selects work assignments rather than pay stubs, because the pay stubs don't exist yet. The work assignments come from the payroll's pay schedule. ### Endpoint `POST /pay_stubs/bulk/create` ### Request ```json theme={null} { "payroll_id": ULID, "work_assignments": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { ...pay stub properties... } } ``` #### Request Properties | Property | Type | Required | Description | | -------------------------- | -------------------------- | -------- | -------------------------------------------------- | | `payroll_id` | ULID | Yes | ID of the payroll to create the pay stubs under | | `work_assignments.include` | criteria object or `"all"` | Yes | Criteria for selecting work assignments to include | | `work_assignments.exclude` | criteria object | No | Criteria for selecting work assignments to exclude | | `data` | object | No | The properties to apply to each created pay stub | #### Work Assignment Criteria Objects `include` and `exclude` can be objects with one or more of the following properties: * `ids`: Array of work assignment IDs to include or exclude * `payee_type`: `"employee"` or `"contractor"` * `pay_schedule_id`: ID of the pay schedule to include or exclude * `archived`: `true` to select archived work assignments, `false` (default) to select active ones * `payee_names`: Name search (partial match) When you combine properties, they apply together. `include` can also be the string `"all"` to include all work assignments on the payroll's pay schedule. #### Data Properties The `data` object contains the pay stub properties to apply to each created pay stub: | Property | Description | | ---------------- | ----------------------------------------------------------------------------------------------- | | `payment_method` | Payment method for the pay stub. Must match the business entity's locked payment method, if set | | `note` | A note on the pay stub | | `external_ref` | Your external identifier for the pay stub | The payroll and work assignment for each pay stub come from your selection. Don't set `payroll_id` or `work_assignment_id` in `data`. These properties are documented in more detail in the API reference for pay stubs. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. See [Asynchronous Execution](#asynchronous-execution) for how to track completion. **⚠️ Partners must treat any 200-level response as success. ⚠️** For example, the response might look like: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "processing", "completed_at": null, "results": [], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:32Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` Once the task completes, `data.results` will contain one entry per created pay stub: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "completed", "completed_at": "2026-05-19T16:14:35Z", "results": [ { "id": "payst_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "pay_stub" }, { "id": "payst_01KBMZDVV9G7713DJRYP9RJFTP", "object": "pay_stub" } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The payroll must be a once-off, historical, correction, or custom-schedule payroll in `draft` status. Regular scheduled payrolls are rejected. * The same pay stub properties are applied to every created pay stub. * Work assignments that already have a pay stub on the payroll are skipped. There is one pay stub per work assignment per payroll. Skipped work assignments won't appear in `data.results`. * Each created pay stub's totals are recalculated after creation, populating any managed line items the work assignment's configuration produces. * Validation runs against every selected work assignment before any pay stub is created. If validation fails, no pay stubs are created. * Invalid work assignment IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. ### Examples #### Create a pay stub for every work assignment on the payroll's pay schedule `POST /pay_stubs/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" } } ``` #### Create pay stubs for specific work assignments with a note `POST /pay_stubs/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "ids": [ "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "wrkas_01J8KXB7P2MQVW4RXZN6Y8H3F1" ] } }, "data": { "note": "Q4 bonus run" } } ``` #### Create pay stubs for all employees, excluding contractors `POST /pay_stubs/bulk/create` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all", "exclude": { "payee_type": "contractor" } } } ``` ## Bulk Create Pay Stubs Scope The create scope endpoint previews which work assignments will receive a new pay stub from a bulk create operation. It accepts the same request body as the bulk create endpoint, but instead of creating pay stubs, it returns the work assignments that match the criteria. Because the pay stubs don't exist yet, this endpoint returns *work assignments*, not pay stubs. Work assignments that already have a pay stub on the payroll are excluded, matching the create behavior. This is useful for confirming which work assignments a bulk create will affect before executing it. ### Endpoint `POST /pay_stubs/bulk/create/scope` ### Request The request body is the same as the [bulk create](#bulk-create-pay-stubs) endpoint. ### Response On success, the operation will return `200 OK` with an array of the work assignments that the bulk create would create pay stubs for: ```json theme={null} { "data": [ { "id": "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "data": { ...work assignment properties... } }, ... ] } ``` ## Bulk Update Pay Stubs Nmbr's API allows you to update select pay stubs within a single payroll. This endpoint is useful when you need to set the same property on a group of pay stubs in one API call, such as adding a note or changing the payment method. ### Endpoint `POST /pay_stubs/bulk/update` ### Request ```json theme={null} { "payroll_id": ULID, "pay_stubs": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { ...properties to update... } } ``` #### Request Properties | Property | Type | Required | Description | | ------------------- | -------------------------- | -------- | -------------------------------------------------- | | `payroll_id` | ULID | Yes | ID of the payroll containing the pay stubs | | `pay_stubs.include` | criteria object or `"all"` | Yes | Criteria for selecting pay stubs to include | | `pay_stubs.exclude` | criteria object | No | Criteria for selecting pay stubs to exclude | | `data` | object | Yes | The properties to update on the matching pay stubs | #### Pay Stub Criteria Objects `include` and `exclude` can be objects with one or more of the following properties: * `ids`: Array of pay stub IDs to include or exclude * `work_assignment_ids`: Array of work assignment IDs. Selects the pay stubs for those work assignments * `payee_type`: `"employee"` or `"contractor"` `include` can also be the string `"all"` to include all pay stubs on the payroll. #### Data Properties The `data` object contains the pay stub properties to update: | Property | Description | | ---------------- | ----------------------------------------------------------------------------------------------- | | `payment_method` | Payment method for the pay stub. Must match the business entity's locked payment method, if set | | `note` | A note on the pay stub | | `external_ref` | Your external identifier for the pay stub | ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the updated pay stubs. See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Pay Stubs β€Ί Response](#response) for an example response shape. `data.type` will be `bulk_update`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. If any matched pay stub fails per-model validation, the entire request fails and no pay stubs are updated. ### Notes * The payroll must be a once-off, historical, correction, or custom-schedule payroll in `draft` status. Regular scheduled payrolls are rejected. * The same update properties are applied to all selected pay stubs. * The operation only affects pay stubs within the specified payroll. * Invalid pay stub IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. ### Examples #### Add a note to every pay stub in a payroll `POST /pay_stubs/bulk/update` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" }, "data": { "note": "Reviewed by payroll admin" } } ``` #### Update the pay stubs for specific work assignments `POST /pay_stubs/bulk/update` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "work_assignment_ids": ["wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } }, "data": { "external_ref": "run-2026-04-offcycle" } } ``` ## Bulk Update Pay Stubs Scope The update scope endpoint previews which pay stubs will be updated by a bulk update operation. It accepts the same request body as the bulk update endpoint, but instead of updating pay stubs, it returns the pay stubs that match the criteria. ### Endpoint `POST /pay_stubs/bulk/update/scope` ### Request The request body is the same as the [bulk update](#bulk-update-pay-stubs) endpoint. ### Response On success, the operation will return `200 OK` with an array of the pay stubs that would be updated: ```json theme={null} { "data": [ { "id": "payst_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...pay stub properties... } }, ... ] } ``` ## Bulk Delete Pay Stubs Nmbr's API allows you to delete select pay stubs within a single payroll. This endpoint is useful when you need to remove a group of pay stubs from an off-cycle or historical payroll in one API call. ### Endpoint `POST /pay_stubs/bulk/delete` ### Request ```json theme={null} { "payroll_id": ULID, "pay_stubs": { "include": "all" | criteria object, "exclude": criteria object (optional) } } ``` #### Request Properties | Property | Type | Required | Description | | ------------------- | -------------------------- | -------- | ------------------------------------------- | | `payroll_id` | ULID | Yes | ID of the payroll containing the pay stubs | | `pay_stubs.include` | criteria object or `"all"` | Yes | Criteria for selecting pay stubs to include | | `pay_stubs.exclude` | criteria object | No | Criteria for selecting pay stubs to exclude | #### Pay Stub Criteria Objects `include` and `exclude` can be objects with one or more of the following properties: * `ids`: Array of pay stub IDs to include or exclude * `work_assignment_ids`: Array of work assignment IDs. Selects the pay stubs for those work assignments * `payee_type`: `"employee"` or `"contractor"` `include` can also be the string `"all"` to include all pay stubs on the payroll. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the deleted pay stubs (still surfaced by ID - the records soft-delete and remain queryable). See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Pay Stubs β€Ί Response](#response) for an example response shape. `data.type` will be `bulk_delete`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The payroll must be a once-off, historical, correction, or custom-schedule payroll in `draft` status. Regular scheduled payrolls are rejected. * The operation only affects pay stubs within the specified payroll. * Invalid pay stub IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. ### Examples #### Delete every pay stub in a payroll `POST /pay_stubs/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": "all" } } ``` #### Delete pay stubs for specific work assignments `POST /pay_stubs/bulk/delete` ```json theme={null} { "payroll_id": "payrl_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_stubs": { "include": { "work_assignment_ids": [ "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "wrkas_01J8KXB7P2MQVW4RXZN6Y8H3F1" ] } } } ``` ## Bulk Delete Pay Stubs Scope The delete scope endpoint previews which pay stubs will be deleted by a bulk delete operation. It accepts the same request body as the bulk delete endpoint, but instead of deleting pay stubs, it returns the pay stubs that match the criteria. ### Endpoint `POST /pay_stubs/bulk/delete/scope` ### Request The request body is the same as the [bulk delete](#bulk-delete-pay-stubs) endpoint. ### Response On success, the operation will return `200 OK` with an array of the pay stubs that would be deleted: ```json theme={null} { "data": [ { "id": "payst_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...pay stub properties... } }, ... ] } ``` # Bulk Recurrence Operations Source: https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-recurrence-operations ## Asynchronous Execution Bulk recurrence operations are asynchronous. Every bulk endpoint returns an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle that you use to track completion and retrieve the affected entities. The task **may or may not have completed** by the time you receive the response β€” `data.status` could be `processing` or `completed`. **Partners must always check `data.status` and not assume the work has finished.** You have two ways to observe completion: * **Poll** the URL in `links.self` on the response until `data.status` is `completed` (or `error`). * **Subscribe** to the [`async_task_completed`](/api/overview/webhook-structure) webhook event, which fires when the task finishes, whether it succeeded or failed. The webhook carries no status. Fetch the task to see how it ended: `data.status` is `completed` on success and `error` on failure. See [Failed Tasks](/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks). `data.results` contains one entry per affected recurrence β€” only the `id` and `object`. To retrieve full recurrence bodies, follow up with a list query (filtered by the returned IDs) or fetch individual entities by ID. Note: scope endpoints (`/bulk/*/scope`) are previews with no side effects and are synchronous - they return `200 OK` with the inline list of matched entities. ## Bulk Create Recurrences Nmbr's API allows you to create a recurrence for select work assignments within a single business entity. This endpoint is useful when you need to create recurrences on one or more work assignments in one API call, such as adding a recurring allowance or benefit to a group of employees. ### Endpoint `POST /s/bulk/create` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `pay_rate` * `reimbursement` For `overtime_rate` bulk operations, see [Bulk Overtime Rate Operations](#bulk-overtime-rate-operations) below. ### Request ```json theme={null} { "business_entity_id": ULID, "work_assignments": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { ...type-specific recurrence properties... } } ``` #### Request Properties | Property | Type | Required | Description | | -------------------------- | -------------------------- | -------- | --------------------------------------------------------- | | `business_entity_id` | ULID | Yes | ID of the business entity containing the work assignments | | `work_assignments.include` | criteria object or `"all"` | Yes | Criteria for selecting work assignments to include | | `work_assignments.exclude` | criteria object | No | Criteria for selecting work assignments to exclude | | `data` | object | Yes | The properties of the recurrence to create | The `data` object contains any recurrence properties specific to the type of recurrence being created. For example, for allowances: | Property | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------ | | `allowance_type` | Type of allowance (e.g., `"cell_phone_allowance"`, `"internet_allowance"`, `"taxable_cash_allowance"`) | | `business_preset_id` | ID of a business preset to use as template | | `title` | Title for the recurrence | | `amount` | Amount for the recurrence | | `frequency` | Frequency for the recurrence (e.g., `"once"`, `"per_payroll"`, `"per_month"`) | | `expense_accounting_code_id` | ID of the expense accounting code | | `liability_accounting_code_id` | ID of the liability accounting code | | `effective_from` | Date the recurrence begins | | `effective_to` | Date the recurrence ends | These properties are documented in more detail in the API reference for each recurrence type. #### Request Criteria Objects `include` and `exclude` can be objects with one of the following properties: * `ids`: Array of work assignment IDs to include or exclude * `payee_type`: `"employee"` or `"contractor"` * `pay_schedule_id`: ID of the pay schedule to include or exclude * `archived`: `true` to include archived work assignments, `false` (default) to exclude them `include` can also be the string `"all"` to include all work assignments. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. See [Asynchronous Execution](#asynchronous-execution) for how to track completion. **⚠️ Partners must treat any 200-level response as success. ⚠️** For example, the response might look like: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "processing", "completed_at": null, "results": [], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:32Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` Once the task completes, `data.results` will contain one entry per created recurrence: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "completed", "completed_at": "2026-05-19T16:14:35Z", "results": [ { "id": "alw_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "allowance" }, { "id": "alw_01KBMZDVV9G7713DJRYP9RJFTP", "object": "allowance" } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The same recurrence properties will be applied to all selected work assignments. * When using a `business_preset_id`, properties must either be omitted or match the preset's values. * The operation only affects work assignments within the specified business entity. Work assignments in other business entities will not be affected. * Invalid work assignment IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. ### Examples #### Create a recurring allowance on all work assignments `POST /allowances/bulk/create` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "data": { "allowance_type": "cell_phone_allowance", "title": "Cell Phone Allowance", "amount": 100.0, "frequency": "per_payroll", "effective_from": "2026-01-01" } } ``` #### Create a recurring allowance using a business preset `POST /allowances/bulk/create` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "data": { "business_preset_id": "rps_01J8KXD3M7RQWN2FXZV9Y4H6B1", "amount": 100.0, "frequency": "per_payroll", "effective_from": "2026-01-01" } } ``` #### Create recurring allowances for specific work assignments `POST /allowances/bulk/create` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "ids": [ "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "wrkas_01J8KXB7P2MQVW4RXZN6Y8H3F1", "wrkas_01J8KXBA3TWQNM7FXZR9Y2V5C4" ] } }, "data": { "allowance_type": "cell_phone_allowance", "title": "Cell Phone Allowance", "amount": 100.0, "frequency": "per_payroll", "effective_from": "2026-01-01" } } ``` #### Create recurring allowances on all employee work assignments, excluding specific work assignments (and implicitly excluding contractor work assignments) `POST /allowances/bulk/create` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "payee_type": "employee" }, "exclude": { "ids": ["wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } }, "data": { "allowance_type": "cell_phone_allowance", "title": "Cell Phone Allowance", "amount": 100.0, "frequency": "per_payroll", "expense_accounting_code_id": "accod_01J8KXF2N4MQRW3VXZH7Y9B5C8", "liability_accounting_code_id": "accod_01J8KXF5P6RQNW4MXZV8Y2H7F1", "effective_from": "2026-01-01" } } ``` ## Bulk Create Recurrences Scope The create scope endpoint previews which work assignments will have new recurrences created on them by a bulk create operation. It accepts the same request body as the bulk create endpoint, but instead of creating recurrences, it returns the work assignments that match the criteria. This is useful for confirming which work assignments a bulk create will affect before executing it. ### Endpoint `POST /s/bulk/create/scope` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `pay_rate` * `reimbursement` For `overtime_rate` bulk operations, see [Bulk Overtime Rate Operations](#bulk-overtime-rate-operations) below. ### Request The request body is the same as the [bulk create](#bulk-create-recurrences) endpoint. ### Response On success, the operation will return `200 OK` with an array of work assignments that the bulk create would create recurrences on: ```json theme={null} { "data": [ { "id": "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "data": { ...work assignment properties... } }, ... ] } ``` ## Bulk Update Recurrences Nmbr's API allows you to update all recurrences of a single type on select work assignments within a single business entity. This endpoint is useful when you need to update the same property on one or more recurrences in one API call, such as changing the amount or accounting code on a group of recurrences. ### Endpoint `POST /s/bulk/update` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `pay_rate` * `reimbursement` For `overtime_rate` bulk operations, see [Bulk Overtime Rate Operations](#bulk-overtime-rate-operations) below. ### Request ```json theme={null} { "business_entity_id": "string", "work_assignments": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "business_presets": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "expense_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "liability_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "data": { ...properties to update... } } ``` #### Request Properties | Property | Type | Required | Description | | ---------------------------------------- | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `business_entity_id` | ULID | Yes | ID of the business entity containing the work assignments | | `work_assignments.include` | criteria object or `"all"` | Yes | Criteria for selecting work assignments to include | | `work_assignments.exclude` | criteria object | No | Criteria for selecting work assignments to exclude | | `business_presets.include.ids` | array of ULIDs or `null` | No | Only update recurrences with one of these business preset IDs. Use `null` to match recurrences with no business preset. | | `business_presets.exclude.ids` | array of ULIDs or `null` | No | Exclude recurrences with one of these business preset IDs. Use `null` to exclude recurrences with no business preset. | | `expense_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only update recurrences with one of these expense accounting code IDs. Use `null` to match recurrences with no expense accounting code. | | `expense_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude recurrences with one of these expense accounting code IDs. Use `null` to exclude recurrences with no expense accounting code. | | `liability_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only update recurrences with one of these liability accounting code IDs. Use `null` to match recurrences with no liability accounting code. | | `liability_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude recurrences with one of these liability accounting code IDs. Use `null` to exclude recurrences with no liability accounting code. | | `data` | object | Yes | The properties to update on the matching recurrences | The `data` object contains any recurrence properties to update. These are the same properties accepted by the single-resource update endpoint for each recurrence type, and are documented in the API reference for each type. #### Work Assignment Criteria Objects `include` and `exclude` can be objects with one of the following properties: * `ids`: Array of work assignment IDs to include or exclude * `payee_type`: `"employee"` or `"contractor"` * `pay_schedule_id`: ID of the pay schedule to include or exclude * `archived`: `true` to include archived work assignments, `false` (default) to exclude them `include` can also be the string `"all"` to include all work assignments. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the updated recurrences. See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Recurrences β€Ί Response](#response) for an example response shape β€” `data.type` will be `bulk_update`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. If any recurrence fails per-model validation, the entire request fails and no recurrences are updated. ### Notes * The same update properties will be applied to all selected recurrences. * The operation only affects work assignments within the specified business entity. * The `work_assignments` criteria select which work assignments to look under. The `business_presets`, `expense_accounting_codes`, and `liability_accounting_codes` criteria further filter which recurrences under those work assignments are updated. ### Examples #### Update the amount on all recurring allowances `POST /allowances/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "data": { "amount": 150.0 } } ``` #### Update the accounting code on all recurring allowances from a specific business preset `POST /allowances/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "business_presets": { "include": { "ids": ["rps_01J8KXD3M7RQWN2FXZV9Y4H6B1"] } }, "data": { "expense_accounting_code_id": "accod_01J8KXF2N4MQRW3VXZH7Y9B5C8" } } ``` #### Update recurring allowances that have no business preset `POST /allowances/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "business_presets": { "include": { "ids": [null] } }, "data": { "amount": 200.0 } } ``` ## Bulk Update Recurrences Scope The update scope endpoint previews which recurrences will be updated by a bulk update operation. It accepts the same request body as the bulk update endpoint, but instead of updating recurrences, it returns the recurrences that match the criteria. ### Endpoint `POST /s/bulk/update/scope` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `pay_rate` * `reimbursement` For `overtime_rate` bulk operations, see [Bulk Overtime Rate Operations](#bulk-overtime-rate-operations) below. ### Request The request body is the same as the [bulk update](#bulk-update-recurrences) endpoint. ### Response On success, the operation will return `200 OK` with an array of the recurrences that would be updated: ```json theme={null} { "data": [ { "id": "alw_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...recurrence properties... } }, ... ] } ``` ## Bulk Delete Recurrences Nmbr's API allows you to delete all recurrences of a single type on select work assignments within a single business entity. This endpoint is useful when you need to remove recurrences on one or more work assignments in one API call. **Important:** This operation deletes ALL recurrences of the specified type on the work assignments, not specific recurrences. If you want to delete specific recurrences, you should use the batch delete recurrences endpoints instead. ### Endpoint `POST /s/bulk/delete` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `pay_rate` * `reimbursement` For `overtime_rate` bulk operations, see [Bulk Overtime Rate Operations](#bulk-overtime-rate-operations) below. ### Request ```json theme={null} { "business_entity_id": "string", "work_assignments": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "business_presets": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "expense_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } }, "liability_accounting_codes": { "include": { "ids": [...] }, "exclude": { "ids": [...] } } } ``` #### Request Properties | Property | Type | Required | Description | | ---------------------------------------- | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `business_entity_id` | ULID | Yes | ID of the business entity containing the work assignments | | `work_assignments.include` | criteria object or `"all"` | Yes | Criteria for selecting work assignments to include | | `work_assignments.exclude` | criteria object | No | Criteria for selecting work assignments to exclude | | `business_presets.include.ids` | array of ULIDs or `null` | No | Only delete recurrences with one of these business preset IDs. Use `null` to match recurrences with no business preset. | | `business_presets.exclude.ids` | array of ULIDs or `null` | No | Exclude recurrences with one of these business preset IDs. Use `null` to exclude recurrences with no business preset. | | `expense_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only delete recurrences with one of these expense accounting code IDs. Use `null` to match recurrences with no expense accounting code. | | `expense_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude recurrences with one of these expense accounting code IDs. Use `null` to exclude recurrences with no expense accounting code. | | `liability_accounting_codes.include.ids` | array of ULIDs or `null` | No | Only delete recurrences with one of these liability accounting code IDs. Use `null` to match recurrences with no liability accounting code. | | `liability_accounting_codes.exclude.ids` | array of ULIDs or `null` | No | Exclude recurrences with one of these liability accounting code IDs. Use `null` to exclude recurrences with no liability accounting code. | #### Work Assignment Criteria Objects `include` and `exclude` can be objects with one of the following properties: * `ids`: Array of work assignment IDs to include or exclude * `payee_type`: `"employee"` or `"contractor"` * `pay_schedule_id`: ID of the pay schedule to include or exclude * `archived`: `true` to include archived work assignments, `false` (default) to exclude them `include` can also be the string `"all"` to include all work assignments. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the deleted recurrences (still surfaced by ID β€” the records soft-delete and remain queryable). See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Recurrences β€Ί Response](#response) for an example response shape β€” `data.type` will be `bulk_delete`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The operation only affects work assignments within the specified business entity. Work assignments in other business entities will not be affected. * Invalid work assignment IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. * The `work_assignments` criteria select which work assignments to look under. The `business_presets`, `expense_accounting_codes`, and `liability_accounting_codes` criteria further filter which recurrences under those work assignments are deleted. ### Examples #### Delete all recurring allowances on all work assignments in a business\_entity `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" } } ``` #### Delete recurring allowances on specific work assignments `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "ids": [ "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "wrkas_01J8KXB7P2MQVW4RXZN6Y8H3F1", "wrkas_01J8KXBA3TWQNM7FXZR9Y2V5C4" ] } } } ``` #### Delete recurring allowances for all employees, excluding specific work assignments `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "payee_type": "employee" }, "exclude": { "ids": ["wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } } } ``` #### Delete recurring allowances for all work assignments except contractors `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all", "exclude": { "payee_type": "contractor" } } } ``` #### Delete only recurring allowances from a specific business preset `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "business_presets": { "include": { "ids": ["rps_01J8KXD3M7RQWN2FXZV9Y4H6B1"] } } } ``` #### Delete recurring allowances that have no business preset `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "business_presets": { "include": { "ids": [null] } } } ``` #### Delete recurring allowances with a specific expense accounting code `POST /allowances/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "expense_accounting_codes": { "include": { "ids": ["accod_01J8KXF2N4MQRW3VXZH7Y9B5C8"] } } } ``` ## Bulk Delete Recurrences Scope The delete scope endpoint previews which recurrences will be deleted by a bulk delete operation. It accepts the same request body as the bulk delete endpoint, but instead of deleting recurrences, it returns the recurrences that match the criteria. ### Endpoint `POST /s/bulk/delete/scope` `` can be one of the following types: * `allowance` * `deduction` * `earning` * `employee_benefit` * `employer_benefit` * `pay_rate` * `reimbursement` For `overtime_rate` bulk operations, see [Bulk Overtime Rate Operations](#bulk-overtime-rate-operations) below. ### Request The request body is the same as the [bulk delete](#bulk-delete-recurrences) endpoint. ### Response On success, the operation will return `200 OK` with an array of the recurrences that would be deleted: ```json theme={null} { "data": [ { "id": "alw_01J8KXC9R4MQVW2FXZN7Y5H3B8", "data": { ...recurrence properties... } }, ... ] } ``` ## Bulk Overtime Rate Operations Overtime rate bulk operations follow the same shape as the other recurrence bulk operations, with one addition: because an overtime rate is attached to a pay rate (not directly to a work assignment), the request body accepts a `pay_rates` criteria block to further narrow the pay rates the operation applies to within the matching work assignments. ### Endpoints * `POST /overtime_rates/bulk/create` * `POST /overtime_rates/bulk/create/scope` * `POST /overtime_rates/bulk/update` * `POST /overtime_rates/bulk/update/scope` * `POST /overtime_rates/bulk/delete` * `POST /overtime_rates/bulk/delete/scope` ### Request ```json theme={null} { "business_entity_id": ULID, "work_assignments": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "pay_rates": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { ...overtime rate properties... } } ``` Update and delete requests additionally accept the `business_presets`, `expense_accounting_codes`, and `liability_accounting_codes` filters described in the [Bulk Update Recurrences](#bulk-update-recurrences) section. #### Pay Rate Criteria Objects `pay_rates.include` can be either the string `"all"` or an object with one of: * `ids`: array of pay rate IDs * `subtypes`: array of pay rate types (e.g. `"hourly"`, `"salary"`) `pay_rates.exclude` is optional and accepts the same object shape (without `"all"`). ### Scope The scope variant of each endpoint accepts the same request body and returns the entities the bulk operation would affect: * `bulk/create/scope` returns the pay rates the new overtime rates would be created under. * `bulk/update/scope` returns the overtime rates that would be updated. * `bulk/delete/scope` returns the overtime rates that would be deleted. ### Examples #### Create overtime rates on all hourly pay rates for a business entity `POST /overtime_rates/bulk/create` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "pay_rates": { "include": { "subtypes": ["hourly"] } }, "data": { "rate_multiplier": 1.5 } } ``` #### Delete all overtime rates on specific pay rates `POST /overtime_rates/bulk/delete` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "pay_rates": { "include": { "ids": ["payrt_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } } } ``` # Bulk Work Assignment Operations Source: https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-work-assignment-operations Bulk work assignment operations create or update many work assignments in one API call. They follow the same shape as [Bulk Line Item Operations](./bulk-line-item-operations) and [Bulk Recurrence Operations](./bulk-recurrence-operations), with two differences: * **Create** selects *payees* (employees and contractors) and creates one work assignment per payee on a pay schedule. * **Update** selects *work assignments* directly, within a single business entity. There is no bulk delete for work assignments. ## Asynchronous Execution Bulk work assignment operations are asynchronous. Every bulk endpoint returns an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle that you use to track completion and retrieve the affected entities. The task **may or may not have completed** by the time you receive the response. `data.status` could be `processing` or `completed`. **Partners must always check `data.status` and not assume the work has finished.** You have two ways to observe completion: * **Poll** the URL in `links.self` on the response until `data.status` is `completed` (or `error`). * **Subscribe** to the [`async_task_completed`](/api/overview/webhook-structure) webhook event, which fires when the task finishes, whether it succeeded or failed. The webhook carries no status. Fetch the task to see how it ended: `data.status` is `completed` on success and `error` on failure. See [Failed Tasks](/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks). `data.results` contains one entry per affected work assignment, with only the `id` and `object`. To retrieve full work assignment bodies, follow up with a list query (filtered by the returned IDs) or fetch individual work assignments by ID. Note: scope endpoints (`/bulk/*/scope`) are previews with no side effects and are synchronous - they return `200 OK` with the inline list of matched entities. ## Bulk Create Work Assignments Nmbr's API allows you to create a work assignment for select payees on a single pay schedule. This endpoint is useful when you need to add a group of employees or contractors to a pay schedule in one API call, such as onboarding a new team onto a bi-weekly schedule. ### Endpoint `POST /work_assignments/bulk/create` ### Request ```json theme={null} { "payees": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { "pay_schedule_id": ULID, ...other work assignment properties... } } ``` #### Request Properties | Property | Type | Required | Description | | ---------------- | -------------------------- | -------- | ---------------------------------------------------------------------------- | | `payees.include` | criteria object or `"all"` | Yes | Criteria for selecting payees to include | | `payees.exclude` | criteria object | No | Criteria for selecting payees to exclude | | `data` | object | Yes | The properties of the work assignment to create, including `pay_schedule_id` | The work assignment's business entity is taken from the pay schedule, so there is no top-level `business_entity_id` on create. #### Payee Criteria Objects `include` and `exclude` can be objects with one or more of the following properties: * `ids`: Array of employee/contractor IDs to include or exclude * `payee_type`: `"employee"` or `"contractor"` * `payee_names`: Name search (partial match) * `archived`: `true` to select archived payees, `false` (default) to select active payees When you combine properties, they apply together. For example, `{ "payee_type": "employee", "archived": false }` selects active employees only. `include` can also be the string `"all"` to include all payees. #### Data Properties The `data` object contains the work assignment properties to apply to each created work assignment. For example: | Property | Description | | ----------------- | --------------------------------------------------------------------------------------------------------- | | `pay_schedule_id` | (Required) The pay schedule to create the work assignment on. Sets the work assignment's business entity. | | `title` | Label for the work assignment | | `is_primary` | Whether this is the payee's primary work assignment | | `pay_split_id` | ID of a pay split to apply to the work assignment | | `external_ref` | Your external identifier for the work assignment | | `archived_at` | Date to archive the work assignment (`YYYY-MM-DD`) | | `tax_properties` | Inline tax properties to set on the work assignment | | `tag_assignment` | Tag allocations for the work assignment | The payee for each work assignment comes from your selection. Don't set `employee_id` or `contractor_id` in `data`. These properties are documented in more detail in the API reference for work assignments. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle. See [Asynchronous Execution](#asynchronous-execution) for how to track completion. **⚠️ Partners must treat any 200-level response as success. ⚠️** For example, the response might look like: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "processing", "completed_at": null, "results": [], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:32Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` Once the task completes, `data.results` will contain one entry per created work assignment: ```json theme={null} { "id": "asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB", "object": "async_task", "data": { "type": "bulk_create", "status": "completed", "completed_at": "2026-05-19T16:14:35Z", "results": [ { "id": "wrkas_01J8KXC9R4MQVW2FXZN7Y5H3B8", "object": "work_assignment" }, { "id": "wrkas_01KBMZDVV9G7713DJRYP9RJFTP", "object": "work_assignment" } ], "created_at": "2026-05-19T16:14:32Z", "updated_at": "2026-05-19T16:14:35Z" }, "links": { "self": "/async_tasks/asnct_01KS0G8Z2YD3T9KQNFW1XEA7HB" } } ``` On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. ### Notes * The same work assignment properties (other than the payee) are applied to every created work assignment. * The business entity is taken from the pay schedule. You don't pass a `business_entity_id`. * Payees that already have a work assignment on that pay schedule are skipped. There is one work assignment per pay schedule per payee. Skipped payees won't appear in `data.results`. * Each new work assignment generates its draft pay stubs on upcoming draft payrolls for that pay schedule, the same as creating a single work assignment. * Validation runs against every selected payee before any work assignment is created. If validation fails, no work assignments are created. * Invalid payee IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. ### Examples #### Create work assignments for all employees on a pay schedule `POST /work_assignments/bulk/create` ```json theme={null} { "payees": { "include": { "payee_type": "employee" } }, "data": { "pay_schedule_id": "paysc_01J8KX9R2FMQVW3TNZH5Y7B4C6" } } ``` #### Create work assignments for specific payees `POST /work_assignments/bulk/create` ```json theme={null} { "payees": { "include": { "ids": [ "emp_01J8KXB4N6RQWM2FVZH9Y3T5C8", "emp_01J8KXB7P2MQVW4RXZN6Y8H3F1", "cntct_01J8KXBA3TWQNM7FXZR9Y2V5C4" ] } }, "data": { "pay_schedule_id": "paysc_01J8KX9R2FMQVW3TNZH5Y7B4C6", "title": "Engineering", "is_primary": true } } ``` #### Create work assignments for all payees, excluding specific payees `POST /work_assignments/bulk/create` ```json theme={null} { "payees": { "include": "all", "exclude": { "ids": ["emp_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } }, "data": { "pay_schedule_id": "paysc_01J8KX9R2FMQVW3TNZH5Y7B4C6" } } ``` #### Create work assignments with a pay split for all contractors `POST /work_assignments/bulk/create` ```json theme={null} { "payees": { "include": { "payee_type": "contractor" } }, "data": { "pay_schedule_id": "paysc_01J8KX9R2FMQVW3TNZH5Y7B4C6", "pay_split_id": "paysp_01J8KXD3M7RQWN2FXZV9Y4H6B1" } } ``` ## Bulk Create Work Assignments Scope The create scope endpoint previews which payees will receive a new work assignment from a bulk create operation. It accepts the same request body as the bulk create endpoint, but instead of creating work assignments, it returns the payees that match the criteria. Because the work assignments don't exist yet, this endpoint returns *payees*, not work assignments. Payees that already have a work assignment on the target pay schedule are excluded, matching the create behavior. This is useful for confirming which payees a bulk create will affect before executing it. ### Endpoint `POST /work_assignments/bulk/create/scope` ### Request The request body is the same as the [bulk create](#bulk-create-work-assignments) endpoint. ### Response On success, the operation will return `200 OK` with an array of the payees that the bulk create would create work assignments for. The array can contain both employees and contractors: ```json theme={null} { "data": [ { "id": "emp_01J8KXB4N6RQWM2FVZH9Y3T5C8", "data": { ...employee or contractor properties... } }, ... ] } ``` ## Bulk Update Work Assignments Nmbr's API allows you to update select work assignments within a single business entity. This endpoint is useful when you need to update the same property on a group of work assignments in one API call, such as moving a team onto a pay split or archiving a set of work assignments. ### Endpoint `POST /work_assignments/bulk/update` ### Request ```json theme={null} { "business_entity_id": ULID, "work_assignments": { "include": "all" | criteria object, "exclude": criteria object (optional) }, "data": { ...properties to update... } } ``` #### Request Properties | Property | Type | Required | Description | | -------------------------- | -------------------------- | -------- | --------------------------------------------------------- | | `business_entity_id` | ULID | Yes | ID of the business entity containing the work assignments | | `work_assignments.include` | criteria object or `"all"` | Yes | Criteria for selecting work assignments to include | | `work_assignments.exclude` | criteria object | No | Criteria for selecting work assignments to exclude | | `data` | object | Yes | The properties to update on the matching work assignments | #### Work Assignment Criteria Objects `include` and `exclude` can be objects with one or more of the following properties: * `ids`: Array of work assignment IDs to include or exclude * `payee_type`: `"employee"` or `"contractor"` * `pay_schedule_id`: ID of the pay schedule to include or exclude * `archived`: `true` to select archived work assignments, `false` (default) to select active ones * `payee_names`: Name search (partial match) When you combine properties, they apply together. `include` can also be the string `"all"` to include all work assignments. #### Data Properties The `data` object contains the work assignment properties to update. For example: | Property | Description | | ---------------------- | ------------------------------------------------------------------------------------------- | | `title` | Label for the work assignment | | `is_primary` | Whether this is the payee's primary work assignment | | `pay_split_id` | ID of a pay split to apply to the work assignment | | `external_ref` | Your external identifier for the work assignment | | `archived_at` | Date to archive the work assignment (`YYYY-MM-DD`) | | `tag_assignment` | Replaces the work assignment's tag allocations | | `tag_assignment_patch` | Additively modifies the existing tag allocations. Mutually exclusive with `tag_assignment`. | You cannot change a work assignment's business entity, pay schedule, or payee. Sending `business_entity_id`, `pay_schedule_id`, `employee_id`, or `contractor_id` in `data` fails validation. These properties are documented in more detail in the API reference for work assignments. ### Response On success, the operation returns `202 Accepted` with an [`async_task`](/api-reference/async-tasks/retrieve-an-async-task) handle whose `data.results` enumerates the updated work assignments. See [Asynchronous Execution](#asynchronous-execution) for how to track completion and [Bulk Create Work Assignments β€Ί Response](#response) for an example response shape. `data.type` will be `bulk_update`. **⚠️ Partners must treat any 200-level response as success. ⚠️** On failure, the operation will return `422 Unprocessable Entity` with standard validation messages. If any matched work assignment fails per-model validation, the entire request fails and no work assignments are updated. ### Notes * The same update properties are applied to all selected work assignments. * The operation only affects work assignments within the specified business entity. * You cannot change a work assignment's business entity, pay schedule, or payee. * Validation is all-or-nothing. If any matched work assignment fails validation, the entire request fails and no work assignments are updated. * Invalid work assignment IDs in the `include.ids` or `exclude.ids` arrays are silently ignored and won't cause an error. * When both `include` and `exclude` criteria are provided, exclusions are applied after inclusions. ### Examples #### Update the title on all work assignments `POST /work_assignments/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "data": { "title": "Engineering" } } ``` #### Archive work assignments on a specific pay schedule `POST /work_assignments/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "pay_schedule_id": "paysc_01J8KX9R2FMQVW3TNZH5Y7B4C6" } }, "data": { "archived_at": "2026-06-01" } } ``` #### Update a pay split for all employees, excluding specific work assignments `POST /work_assignments/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": { "payee_type": "employee" }, "exclude": { "ids": ["wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8"] } }, "data": { "pay_split_id": "paysp_01J8KXD3M7RQWN2FXZV9Y4H6B1" } } ``` #### Add a tag to all work assignments without replacing existing allocations `POST /work_assignments/bulk/update` ```json theme={null} { "business_entity_id": "be_01J8KX9R2FMQVW3TNZH5Y7B4C6", "work_assignments": { "include": "all" }, "data": { "tag_assignment_patch": { "add_tags": ["tag_01J8KXF2N4MQRW3VXZH7Y9B5C8"] } } } ``` ## Bulk Update Work Assignments Scope The update scope endpoint previews which work assignments will be updated by a bulk update operation. It accepts the same request body as the bulk update endpoint, but instead of updating work assignments, it returns the work assignments that match the criteria. ### Endpoint `POST /work_assignments/bulk/update/scope` ### Request The request body is the same as the [bulk update](#bulk-update-work-assignments) endpoint. ### Response On success, the operation will return `200 OK` with an array of the work assignments that would be updated: ```json theme={null} { "data": [ { "id": "wrkas_01J8KXB4N6RQWM2FVZH9Y3T5C8", "data": { ...work assignment properties... } }, ... ] } ``` # Authentication Source: https://docs.nmbr.co/api/overview/authentication Authenticating with the nmbr API Nmbr has two categories of tokens that are used throughout development: partner-level tokens (`partner_key`, `partner_secret`) and company-level tokens (`access_token`). You will need to securely manage and store all tokens in your database. ## Partner-Level Tokens Partner-level tokens are issued to Nmbr partners via the developer portal and grant access to create partner-managed companies. Using the `partner_secret` you can create a new partner-managed company. In the header of the request you will include the `partner_secret` using an Authorization HTTP header with the bearer token scheme. ``` Content-Type: application/json Authorization: Bearer ApiTokenAAABBBCCC ``` ## Company-Level Tokens Company-level tokens are scoped for an individual company and are short-lived to improve security practices. The `access_token` can be used to make API requests. After creation of a partner-managed company, you will receive an `access_token`, `expires_in`, and the `id` of the created company to make subsequent API calls on behalf of the company. `expires_in` is the number of minutes in which the `access_token` will expire. ```json theme={null} { "id": "01hgkpjgyspp2nszf8fq7j9c0a", "object": "company", "data": { "name": "Bobs Burgers", "pay_day_movement_setting": "inherit", "status": null, "created_at": "2023-12-01T22:04:19.000000Z", "updated_at": "2023-12-01T22:04:19.000000Z", "token": { "access_token": "1hucWCMptvpPiO5bbsSwuAGICKeFN8mPdAPWlxYQc3d02eb5", "expires_in": 59, "expires_at": "2023-12-01T23:04:19.000000Z" } }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hgkpjgyspp2nszf8fq7j9c0a" } } ``` ## Using Access Tokens You can use `access_tokens` to make requests to the Nmbr API. Use the `access_token` as the Authorization header. ```bash theme={null} curl --location --request GET 'https://sandbox.nmbr.co/services/payroll/employees' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer AccessTokenAAABBBCCC' ``` ## Retrieving new Access Tokens Access tokens expire 1 hour (60 minutes) after they are issued. If an access token is expired you will receive `401 Unauthorized` errors. To retrieve a new access token, you will need the `company_id` along with the `partner_secret` from the developer portal. To retrieve your `access_token` use the POST /token endpoint. ```bash theme={null} curl --location --request POST 'https://sandbox.nmbr.co/services/payroll/token' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {{partner_secret}}' \ --data-raw '{ "company_id": "{{company_id}}" }' ``` The corresponding response will include a new `access_token`. ```json theme={null} { "access_token": "28|CO8zAiFQgA15LpDXCgwb5yp5lswJcSJmN82XFG0B9514ee7a", "expires_in": 59, "expires_at": "2023-12-01T23:07:53.000000Z" } ``` The `expires_in` value is provided in minutes from when the `access_token` was generated. ## Revoking Access Tokens If you need to revoke access tokens, you can do so by calling the DELETE /token endpoint. ```bash theme={null} curl --location --request DELETE 'https://sandbox.nmbr.co/services/payroll/token' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {{partner_secret}}' \ --data-raw '{ "company_id": "{{company_id}}" }' ``` This will revoke all access tokens associated with the specified `company_id`. ## Token Management Recommendations Access tokens are specific to a partner and company. Care should be taken to avoid token refresh race conditions. It is recommended to have unique constraints and when refreshing tokens, lock the associated row. **Example refresh steps:** 1. An access token needs to be refreshed. We know this because the `expires_in` is less than current time or an HTTP status of 401 is received from a Nmbr API request 2. Lock the `auth_tokens` row for the associated `company_id` 3. Refresh the access token as instructed above 4. Update the `auth_tokens` row with the new access tokens. The `expires_at` should also be updated to x minutes from the current time. 5. Unlock the row 6. Use the new `access_token` for Nmbr API requests 7. All concurrent processes should use the latest `access_token` # Idempotency Source: https://docs.nmbr.co/api/overview/idempotency Safely retrying requests Nmbr supports idempotency to allow for safely retrying requests without accidentally performing the same operation twice. This approach is useful for issuing requests that you do not want to happen more than once, such as attaching earning line items to a pay stub. You can retry a request with the same idempotency key while guaranteeing that the request is only performed once. To perform an idempotent request, include an `X-Idempotency-Key` header with a unique key for the specific request. We save the original response for the first request made with a given key. Future requests with the same key return the original response without performing any changes. The format and how you generate the idempotency key is up to you, however we suggest using [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier). ``` X-Idempotency-Key: 71edb1dec791-ac55-1t3y-e918-8ac545e4 ``` # Pagination Source: https://docs.nmbr.co/api/overview/pagination Handle paginated responses from the Nmbr API In our API, responses that return lists of objects are paginated. Pagination breaks down a large response into smaller responses called pages that the caller can step through to read all of the data. Nmbr paginates responses to ensure that response sizes are kept small and response times remain low. ## Paginated Response Endpoints that return a list of objects break the list up into multiple pages of up to 15 objects. For example, a list of 100 employees will be broken down into 7 pages, with the first six pages containing 15 employees each and the last page containing the remaining 10 employees. ```json theme={null} { "object": "list", "data": [ { "id": "", "object": "employee", "data": { }, "links": { "self": "/employees/" } } ], "links": { "first": "/employees?page=1", "last": "/employees?page=1", "prev": null, "next": null }, "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1, "has_more": false } } ``` The `data` property contains the current page of objects. The `links` and `meta` properties contain information about the pagination of the objects, allowing clients to navigate through the paginated data efficiently and correctly. The `links` property contains links to four specific pages of data: * `first`: The URL of the first page of objects. * `last`: The URL of the last page of objects. * `prev`: The URL of the previous page of objects, or `null` if the current page is the first page. * `next`: The URL of the next page of objects, or `null` if the current page is the last page. The `meta` property contains metadata about the pagination: * `current_page`: The page number of the current page of objects. * `last_page`: The page number of the last page of objects, which is the total number of pages in the list. * `per_page`: The number of objects returned per page (15). * `total`: The total number of objects in the list. * `has_more`: `true` if there are more pages available, or `false` if the current page is the last page of objects. # Rate Limits Source: https://docs.nmbr.co/api/overview/rate-limits Request limits, rate-limiting buckets, and handling 429 responses The Nmbr API limits how many requests you can make per minute. Every response tells you how much of your limit is left, and a request that goes over the limit returns `429 Too Many Requests` without being processed. The same limits apply in sandbox and production. ## Limits | Rate-limiting bucket | Limit | Applies to | | -------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | API requests | 1,000 requests per minute | All endpoints unless documented below | | Reveal | 25 requests per minute | The `/reveal` endpoints, such as `GET /employees//reveal` and `GET /bank_accounts//reveal` | Both limits cover the requests you make with your own access tokens. Requests made by the Nmbr Component are counted separately and do not count toward either limit. ## How rate-limiting buckets work A rate-limiting bucket is a counter. Each one counts your requests in a one-minute window. The window opens on your first request and the counter resets 60 seconds later. It is not aligned to the clock minute. **Your allowance is per authenticated entity.** Requests to partner endpoints count against your partner, and requests to company endpoints count against the company in the access token you used. Each company you serve gets its own 1,000 requests per minute, so a busy company can't exhaust another company's allowance. **The reveal bucket is additional.** A call to a `/reveal` endpoint counts against both the reveal bucket and the API requests bucket. Reveal endpoints return sensitive values such as a full Social Insurance Number, so they carry a tighter limit of their own. Read one record at a time and cache what you need rather than revealing a list of employees in a loop. **Nmbr Component traffic does not count toward your API rate limits.** Requests the Component makes for your users go into a rate-limiting bucket of their own, separate from the buckets above. A user working in the Component never consumes the allowance your own integration is spending. ## Rate limit headers Every response carries your standing in the rate-limiting bucket: | Header | Value | | ----------------------- | ---------------------------------------------------- | | `X-RateLimit-Limit` | The maximum number of requests allowed in the window | | `X-RateLimit-Remaining` | The number of requests left in the current window | A `429` response adds two more: | Header | Value | | ------------------- | --------------------------------------------- | | `Retry-After` | The number of seconds to wait before retrying | | `X-RateLimit-Reset` | The Unix timestamp when the window resets | When more than one limit applies to an endpoint, the headers describe the rate-limiting bucket you are closest to exhausting. ## Over the limit **Response** ```http theme={null} HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 Retry-After: 34 X-RateLimit-Reset: 1753912800 ``` ```json theme={null} { "message": "Too Many Attempts." } ``` Wait `Retry-After` seconds, then retry. A `429` means the request never reached the API, so nothing was created, updated, or deleted. If the request carried an `X-Idempotency-Key`, the key was not consumed and you can retry with the same one. See [Idempotency](/api/overview/idempotency). ## Staying under the limit * Use the [bulk and batch endpoints](/api/bulk-and-batch-operations/bulk-and-batch-operations) to write many entities in one request instead of one request per entity. * Use [`expand`](/api/overview/response-structure#expanding-resources) to pull related resources into a single response instead of following each stub with another request. * Back off using `Retry-After` instead of retrying immediately. Retrying in a tight loop keeps you over the limit and delays your own recovery. # Client Request ID Source: https://docs.nmbr.co/api/overview/request-id Tracing requests Nmbr supports tracing your requests using a Client Request ID, which will be included in webhook events. This approach is useful for tracking and correlating requests and their resulting events, especially in complex workflows or when debugging issues. To include a Client Request ID, add an `X-Client-Request-ID` header with a unique identifier for the specific request. This ID will be included in any related webhook events. The format and how you generate the Client Request ID is up to you, however we suggest using [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier). ``` X-Client-Request-ID: 71edb1dec791-ac55-1t3y-e918-8ac545e4 ``` # Responses Source: https://docs.nmbr.co/api/overview/response-structure Viewing and Expanding resources on the Nmbr API ## ULID All Nmbr entities have an `id`. These ids are based on a customized version of [ULIDs](https://github.com/ulid/spec). Nmbr ULIDs take the form of a standard `ULID` prefixed with a namespace reference. For example, an employee may be `emp_01JAV10D4QJ3500QANBTTBW9DW`, and a company may be `cmp_01JAV11013A9V4V0F30099BVGH`. ## Response Structure Objects across the Nmbr API follow a consistent JSON structure, either a single Entity, a Pageable List, or a Non-Pageable List. Entities and Lists can be returned as the root response on an endpoint. ### Entities Entity Responses will follow the structure: ```json theme={null} { "id": string (ULID), "object": string, "data": { // ... }, "links": { "self": string (url) } } ``` ### Pageable Lists Pageable Lists contain up to 15 objects per-page and can be paged using the associated `links` data. The `object` type will always have the value `list` . ```json theme={null} { "object": "list", "data": [ { "id": string (GUID), "object": string, "data": { // ... "created_at": string (ISO-8601), "updated_at":string (ISO-8601) }, "links": { "self": string (url) } } // ... ], "links": { "first": string (url), "last": string (url), "prev": string (url)|null, "next": string (url)|null }, "meta": { "current_page": int, "last_page": int, "per_page": int, "total": int, "has_more": boolean } } ``` ### Non-Pageable Lists Non-Pageable Lists are returned for lists with no related endpoint to page through. In these cases the complete data set will be returned as a `list` with no paging information. ```json theme={null} { "object": "list", "data": [ { "id": string (GUID), "object": string, "data": { // ... }, "links": { "self": url } } // ... ] } ``` ## Related Resources Entities will contain references to other objects - e.g an Employee will contain a Company reference. By default, these will be "stub" entities which will have no `data` attribute. They may be an Entity, a Pageable List or a Non-Pageable List. ```json theme={null} { "id": "01hfwg26zxk6bg8874nth78cgr", "object": "employee", "data": { "company": { "id": "01hfwg25dbyebq330k8c8ammpm", "object": "company", "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hfwg25dbyebq330k8c8ammpm" } }, // ... "created_at": "2023-11-22T21:48:01.000000Z", "updated_at": "2023-11-22T21:48:01.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/employees/01hfwg26zxk6bg8874nth78cgr" } } ``` ## Expanding Resources If you would like to retrieve the `data` of a related resource inline, you may pass the `expand` array parameter to expand its contents. Request: ```bash theme={null} curl 'https://sandbox.nmbr.co/services/payroll/employees/01hfwg26zxk6bg8874nth78cgr?expand[]=company' \ --header 'Authorization: Bearer Llk5NQVFt9bu2auhJBuBxFGih22VecGq8qUeDD0Q7aa0c5bf' ``` Response ```json theme={null} { "id": "01hfwg26zxk6bg8874nth78cgr", "object": "employee", "data": { "company": { "id": "01hfwg25dbyebq330k8c8ammpm", "object": "company", "data": { "name": "Bouchard Inc.", "pay_day_movement_setting": "inherit", "status": "onboarding", "created_at": "2023-11-22T21:47:59.000000Z", "updated_at": "2023-11-22T21:47:59.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hfwg25dbyebq330k8c8ammpm" } }, // ... "created_at": "2023-11-22T21:48:01.000000Z", "updated_at": "2023-11-22T21:48:01.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/employees/01hfwg26zxk6bg8874nth78cgr" } } ``` The API will return "stub" objects to represent related Entities and Lists of related Entities. These objects can be expanded to include their `data` by passing the `expand` parameter in your request. You can expand multiple layers down by defining dot (`.`) notation values to the `expand` array. In the following example, the `company` entity is expanded to a full `company` resource, and its pageable-list of `business_entities` is expanded into a list of `business_entity` resources. Request: ```shell theme={null} curl 'https://sandbox.nmbr.co/services/payroll/employees/01hfwg26zxk6bg8874nth78cgr?expand[]=company.business_entities' \ --header 'Authorization: Bearer Llk5NQVFt9bu2auhJBuBxFGih22VecGq8qUeDD0Q7aa0c5bf' ``` Response: ```json theme={null} { "id": "01hfwg26zxk6bg8874nth78cgr", "object": "employee", "data": { "company": { "id": "01hfwg25dbyebq330k8c8ammpm", "object": "company", "data": { "name": "Bouchard Inc.", "pay_day_movement_setting": "inherit", "status": "onboarding", "business_entities": { "object": "list", "data": [ { "id": "01hfwg25fz7t023he2jr3b2nas", "object": "business_entity", "data": { "business_number": "34y6y3", // ... }, "company": { "id": "01hfwg25dbyebq330k8c8ammpm", "object": "company", "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hfwg25dbyebq330k8c8ammpm" } }, "created_at": "2023-11-22T21:47:59.000000Z", "updated_at": "2023-11-22T21:47:59.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/01hfwg25fz7t023he2jr3b2nas" } } ], "links": { "first": "https://sandbox.nmbr.co/services/payroll/business_entities?page=1", "last": "https://sandbox.nmbr.co/services/payroll/business_entities?page=1", "prev": null, "next": null }, "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1, "has_more": false } }, "created_at": "2023-11-22T21:47:59.000000Z", "updated_at": "2023-11-22T21:47:59.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hfwg25dbyebq330k8c8ammpm" } }, // ... "created_at": "2023-11-22T21:48:01.000000Z", "updated_at": "2023-11-22T21:48:01.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/employees/01hfwg26zxk6bg8874nth78cgr" } } ``` ### Using the `expand` array Multiple objects can be expanded by passing multiple values to the `expand` parameter. Some objects have properties which are arrays of data - if there is an expandable property in such an array, you must pass the dot-property of the `array.property`. For example, to expand the `recurring_allowance` in a `allowance_line_item`, you must pass the parameter `expand[]=allowance.recurring_allowance`. The `expand` parameter can also accept a comma separated list of expandable attributes: `expand=company,allowance.recurring_allowance`. Request ```bash theme={null} curl 'https://sandbox.nmbr.co/services/payroll/allowance_line_items/01hfym068emnp93zxz94822ec5?expand[]=allowance.recurring_allowance' \ --header 'Authorization: Bearer Llk5NQVFt9bu2auhJBuBxFGih22VecGq8qUeDD0Q7aa0c5bf' ``` Response ```json theme={null} { "id": "01hfym068emnp93zxz94822ec5", "object": "allowance_line_item", "data": { "pay_stub": { "id": "01hfwg2784vc1408yhmjp4x81q", "object": "pay_stub", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/01hfwg2784vc1408yhmjp4x81q" } }, "line_item_type": "allowance", "amount": 10, "allowance": { "allowance_type": "automobile_and_motor_vehicle", "recurring_allowance": { "id": "01hfykqhej130bzjfryem64wjv", "object": "recurring_allowance", "data": { "employee": { "id": "01hfwg26zxk6bg8874nth78cgr", "object": "work_assignment", "links": { "self": "https://sandbox.nmbr.co/services/payroll/work_assignments/01hfwg26zxk6bg8874nth78cgr" } }, "allowance_type": "automobile_and_motor_vehicle", "amount": 10, "effective_from": "2023-01-01T00:00:00.000000Z", "effective_to": null, "created_at": "2023-11-23T17:30:34.000000Z", "updated_at": "2023-11-23T17:30:34.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/allowances/01hfykqhej130bzjfryem64wjv" } } }, "created_at": "2023-11-23T17:35:18.000000Z", "updated_at": "2023-11-23T17:35:18.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/allowance_line_items/01hfym068emnp93zxz94822ec5" } } ``` ### Maximum expansion depth `expand` parameters using dot-properties for deep expanding may go up to **4 layers deep**. For example, the following is a valid `expand` argument on a `pay_stub`: `work_assignment.pay_rate.expense_accounting_code.business_entity`. However, no property on the `business_entity` may be expanded. ### Expanding optional properties Some resources will have expandable properties that are not returned by default (i.e no "stub" entity will be returned by default). These optional properties will be documented as available, but must be requested in the `expand` argument to be returned. The `expand` parameter can be used to reduce the total number of requests required to use the Nmbr API, however it should be used only when required, as there may be a noticeable performance difference when querying for a single entity with no `expand` argument, vs a query with multiple `expand` arguments - especially when expanding attributes in a list. ## Error Response Structure When a client error (4xx) occurs, the Nmbr API returns a standardized error response. ### Bad Request (400) A `400` status code indicates that the request was invalid. The response message explains why the request could not be processed. ```json theme={null} { "message": "The action is not allowed after a payroll has been run." } ``` ### Unauthorized (401) A `401` status code indicates that authentication has failed. ```json theme={null} { "message": "Unauthorized" } ``` ### Forbidden (403) A `403` status code indicates that the client does not have permission to perform the requested action. ```json theme={null} { "message": "Forbidden" } ``` ### Not Found (404) A `404` status code indicates that the requested resource does not exist. ```json theme={null} { "message": "Entity not found" } ``` ### Unprocessable Entity (422) A `422` status code is returned when validation errors occur. The response includes a summary message and an `errors` object detailing validation issues for each field. ```json theme={null} { "message": "The selected province code is invalid. (and 2 more errors)", "errors": { "province_code": ["The selected province code is invalid."], "country_code": ["The selected country code is invalid."], "sin": ["Not a valid sin number. Must be a string in format ^[0-9]{9}$"] } } ``` ### Too Many Requests (429) A `429` status code indicates that you have gone over a rate limit. The request was not processed. ```json theme={null} { "message": "Too Many Attempts." } ``` The response includes a `Retry-After` header holding the number of seconds to wait before retrying, along with the `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers. See [Rate Limits](/api/overview/rate-limits). # Warnings Source: https://docs.nmbr.co/api/overview/warnings Information regarding the state of a given resource A number of resources expose a warning object to provide insight into the status of each entity and potential steps that may be blocking future actions such as running payroll. ### Warning Example ```json theme={null} "warnings": { "object": "list", "data": [ { "id": null, "object": "warning", "data": { "namespace": "onboarding", "type": "business_verification_incomplete" }, "links": { "self": null } }, { "id": null, "object": "warning", "data": { "namespace": "onboarding", "type": "business_legal_information_not_provided" }, "links": { "self": null } }, { "id": null, "object": "warning", "data": { "namespace": "onboarding", "type": "bank_account_doesnt_exists" }, "links": { "self": null } }, { "id": null, "object": "warning", "data": { "namespace": "onboarding", "type": "bank_account_unrecognized_institution" }, "links": { "self": null } }, { "id": null, "object": "warning", "data": { "namespace": "onboarding", "type": "bank_account_pad_not_signed" }, "links": { "self": null } } ] }, ``` # Webhooks Source: https://docs.nmbr.co/api/overview/webhook-structure Receiving webhooks based on events ## Registering Webhooks Before receiving webhook calls a webhook URL must be registered using the Webhook API Endpoint. ## Webhook Structure Webhooks across the Nmbr API follow a consistent JSON structure that includes: * the event * the resource * type * identifier * external reference (`external_ref`), if the resource type supports setting an external reference * company identifier, if the resource type is scoped to a company The webhook call made when a business entity is created would have the following properties: ```json theme={null} { "event": "resource_created", "resource": { "type": "business_entity", "id": "", "external_ref": "", "company_id": "" } } ``` The webhook call made when a company is created would have similar properties: ```json theme={null} { "event": "resource_created", "resource": { "type": "company", "id": "", "external_ref": "" } } ``` Note that the call doesn't include the `company_id` property because the resource is the company itself and so its identifier is in the `id` property. The webhook structure does not contain additional entity data. It is recommended the receiving system performs a GET request for the specific entity to retrieve the most up-to-date resource. ## Webhook Security Nmbr will automatically generate a `key` for each webhook created. Any outgoing webhook calls will include a `Webhook-Signature` header with an HMAC SHA256 hash of the payload using the webhook `key`. Consumers may calculate their own signature using the known `key` and payload to compare to the request header. If the resulting signatures match the developer can be confident the request came from Nmbr. ## Webhook Events Most resources support 3 standard events: * `resource_created` * `resource_updated` * `resource_deleted` Some resources have additional events that can be used to determine the state of the resource: * `payroll_approved` `async_task_completed` reports that an [async task](/api-reference/async-tasks/retrieve-an-async-task) reached its final state, whether the work succeeded or failed. Despite the name, it is not a success signal. Fetch the task to read `data.status` (`completed` or `error`) and, on `error`, any failure details in `data.results`. See [Failed Tasks](/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks). The following table outlines each resource and the corresponding supported events. | Resource | Type | Supported Events | | ----------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Accounting Code | `accounting_code` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Accounting Code Rule | `accounting_code_rule` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Adjustment | `adjustment` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Allowance | `allowance` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Async Task | `async_task` |
  • `async_task_completed`
| | Bank Account | `bank_account` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Business Entity | `business_entity` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
  • `integration_authentication_success`
  • `integration_authentication_failure`
  • `integration_sync_account_codes_complete`
  • `integration_sync_account_codes_failure`
  • `integration_sync_tags_complete`
  • `integration_sync_tags_failure`
| | Business Preset | `business_preset` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Company | `company` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Contractor | `contractor` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Deduction | `deduction` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Earning | `earning` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Employee | `employee` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Employee Benefit | `employee_benefit` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Employer Benefit | `employer_benefit` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Form Batch | `form_batch` |
  • `form_batch_completed`
| | Overtime Rate | `overtime_rate` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Pay Rate | `pay_rate` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Pay Schedule | `pay_schedule` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Pay Split | `pay_split` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Pay Stub | `pay_stub` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
  • `pay_stub_available`
| | Payroll | `payroll` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
  • `payroll_approved`
  • `payroll_unapproved`
  • `payroll_paid`
  • `payroll_deadline_upcoming`
  • `integration_sync_journal_entries_complete`
  • `integration_sync_journal_entries_failure`
| | Reimbursement | `reimbursement` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Remittance Account | `remittance_account` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Remittance Account Enrollment | `remittance_account_enrollment` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Tag | `tag` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Tag Group | `tag_group` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Vacation Pay Setting | `vacation_pay_setting` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| | Work Assignment | `work_assignment` |
  • `resource_created`
  • `resource_updated`
  • `resource_deleted`
| # API Source: https://docs.nmbr.co/changelog/api Product updates and announcements ## `async_task_completed` now fires on failure > 🚧 Behaviour Change > The `async_task_completed` webhook now fires when an async task fails, not only when it > succeeds. Check the task's `status` before you act on the event. ### Background An async task ends in one of two states: `completed` when the work succeeded, or `error` when it failed. Until now the `async_task_completed` webhook only fired on `completed`, so a failed task produced no event at all. The only way to notice a failure was to keep polling a task you had otherwise stopped watching. ### What's Changing The webhook now fires as soon as the task reaches either state. It reports that the task is done, not that it worked. The payload is unchanged, and it does not carry the status. Fetch the task with the ID from the webhook and read `data.status`: * `completed`: the work succeeded. `completed_at` is set, and `data.results` lists the affected entities. * `error`: the work failed. `completed_at` stays `null`. For batch operations, `data.results` names the entities that could not be written, each with `status` set to `error` and a message in `error`. If your integration treats an `async_task_completed` event as proof of success, add a `data.status` check before it goes any further. See [Failed Tasks](https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-and-batch-operations#failed-tasks). ## Deprecating root-level data properties on bulk endpoints > 🚧 Breaking Change > Bulk endpoints will stop accepting data properties on the root of the request in a > future release. Data properties should be nested under a `data` key. The old format > continues to work for now but is deprecated. ### Background Bulk create and update endpoints accept two types of properties in the request body: * **Filter properties**: Properties used to select the entities to operate on (e.g. `payroll_id`, `pay_stubs`). * **Data properties**: Properties for the created or updated entities (e.g. `deduction_type`, `custom_amount`). When we first introduced bulk endpoints, both types of properties were placed on the root of the request body. However, some bulk endpoints need filter and data properties with the same name but different values. To support this, we're moving data properties into a nested `data` key. ### What's Changing Data properties should be nested under a `data` key in the request body. For example, instead of sending data properties on the root of the request: Legacy request with data properties on root ``` POST /deduction_line_items/bulk/create { "payroll_id": "payrl_01JBC4F2XKMP7R9QHN3DSWV6YA", "pay_stubs": { "include": { "ids": [ "payst_01JBC4F8GT5YNWZ0CRHQ6DMXKE", "payst_01JBC4FBMS3AP4VD7TXJW2HN9R" ] } }, "deduction_type": "union_dues", "title": "Union Dues", "custom_amount": 50, "custom_hours": null } ``` nest the data properties under a `data` key: Modern request with data properties nested under `data` ``` POST /deduction_line_items/bulk/create { "payroll_id": "payrl_01JBC4F2XKMP7R9QHN3DSWV6YA", "pay_stubs": { "include": { "ids": [ "payst_01JBC4F8GT5YNWZ0CRHQ6DMXKE", "payst_01JBC4FBMS3AP4VD7TXJW2HN9R" ] } }, "data": { "deduction_type": "union_dues", "title": "Union Dues", "custom_amount": 50, "custom_hours": null } } ``` ### Migrating to the `data` Key To help preexisting partners migrate their integrations, you can force either behavior by passing a `Prefer` header with the request: * To require data properties under `data`: `Prefer: deprecate_flat_bulk_shape=true` * To keep accepting data properties on the root: `Prefer: deprecate_flat_bulk_shape=false` When the `data` key is required, any data property sent on the root is rejected with a `422`, with one validation error per misplaced property. We recommend migrating as soon as possible by passing `Prefer: deprecate_flat_bulk_shape=true` on all bulk requests. Once your integration is fully migrated to the `data` key, contact Nmbr support to make this the default behavior for your partner. After that, you can remove the `Prefer` headers from your requests. ### Affected Endpoints Recurrence bulk endpoints: * `POST /allowances/bulk/create` * `POST /allowances/bulk/update` * `POST /deductions/bulk/create` * `POST /deductions/bulk/update` * `POST /earnings/bulk/create` * `POST /earnings/bulk/update` * `POST /employee_benefits/bulk/create` * `POST /employee_benefits/bulk/update` * `POST /employer_benefits/bulk/create` * `POST /employer_benefits/bulk/update` * `POST /reimbursements/bulk/create` * `POST /reimbursements/bulk/update` * `POST /pay_rates/bulk/create` * `POST /pay_rates/bulk/update` * `POST /overtime_rates/bulk/create` * `POST /overtime_rates/bulk/update` Line item bulk endpoints: * `POST /allowance_line_items/bulk/create` * `POST /allowance_line_items/bulk/update` * `POST /deduction_line_items/bulk/create` * `POST /deduction_line_items/bulk/update` * `POST /earning_line_items/bulk/create` * `POST /earning_line_items/bulk/update` * `POST /employee_benefit_line_items/bulk/create` * `POST /employee_benefit_line_items/bulk/update` * `POST /employer_benefit_line_items/bulk/create` * `POST /employer_benefit_line_items/bulk/update` * `POST /reimbursement_line_items/bulk/create` * `POST /reimbursement_line_items/bulk/update` Other bulk endpoints: * `POST /remittance_account_enrollments/bulk/create` * `POST /work_assignments/bulk/create` * `POST /work_assignments/bulk/update` ### What's Not Changing Filter properties (`payroll_id`, `pay_stubs`, etc.) remain on the root of the request body. Only data properties are moving into the `data` key. The old format with data properties on the root of the request continues to work for preexisting partners, but will be removed in a future release. The nested `data` shape is the default for new partners going forward. ## Deprecating the legacy `percent` field on benefits > 🚧 Breaking Change > The `percent` field on employee and employer benefits will be removed in a future > release. Percentage-based benefits are represented with `amount` and an `amount_type` of > `percent`. The old `percent` field continues to work for now but is deprecated. ### Background A benefit's contribution can be either a fixed dollar amount or a percentage. Historically these were represented with two separate, mutually exclusive fields: * **`amount`**: The fixed dollar amount. Set on fixed benefits, `null` on percentage benefits. * **`percent`**: The percentage. Set on percentage benefits, `null` on fixed benefits. Having two fields where only one is ever populated made benefits awkward to work with: callers had to choose the right field and always handle a `null` for the other. It was also inconsistent with other recurrence types that support percentage values - deductions, for example, already use a single `amount` field paired with an `amount_type` discriminator. We're bringing benefits in line by replacing `percent` with the same `amount` + `amount_type` shape. ### What's Changing Percentage-based benefits are now represented with a single `amount` value and an `amount_type` of `percent`, instead of the separate `percent` field. Fixed benefits use the same `amount` value with an `amount_type` of `fixed`. Instead of sending a `percent` field when creating or updating a percentage-based benefit: Legacy request using the `percent` field ``` POST /employee_benefits { "work_assignment_id": "wrkas_01JBC4F2XKMP7R9QHN3DSWV6YA", "employee_benefit_type": "pension_rrsp", "frequency": "per_pay_period", "effective_from": "2026-01-01", "percent": 5 } ``` send the value in `amount` with an `amount_type` of `percent`: Modern request using `amount` and `amount_type` ``` POST /employee_benefits { "work_assignment_id": "wrkas_01JBC4F2XKMP7R9QHN3DSWV6YA", "employee_benefit_type": "pension_rrsp", "frequency": "per_pay_period", "effective_from": "2026-01-01", "amount": 5, "amount_type": "percent" } ``` Fixed benefits set `amount_type` to `fixed`: ``` { "amount": 100, "amount_type": "fixed" } ``` Benefit responses change to match. Instead of returning both `amount` and `percent` with one always `null`: Legacy response ``` { ... "amount": null, "percent": 5 } ``` responses return a single `amount` alongside `amount_type` and omit `percent`: Modern response ``` { ... "amount": 5, "amount_type": "percent" } ``` In the modern shape `amount` holds the value for **both** types: it is a dollar amount when `amount_type` is `fixed` and a percentage when `amount_type` is `percent`. Use `amount_type` to interpret it. `amount_type` itself is a new field introduced by this change; benefit responses did not previously return it. It now appears in both shapes, so partners who stay on the legacy shape will start receiving `amount_type` alongside the existing `amount` and `percent` fields. This is additive - no existing field is removed or changed for the legacy shape. ### Migrating to `amount` and `amount_type` To help preexisting partners migrate their integrations, you can force either shape by passing a `Prefer` header with the request: * To use the modern shape: `Prefer: deprecate_benefit_percent=true` * To use the legacy shape: `Prefer: deprecate_benefit_percent=false` The header controls both how the request body is interpreted and how the response is shaped. We recommend migrating as soon as possible by passing `Prefer: deprecate_benefit_percent=true` on all benefit requests. The modern shape is the default for new partners going forward. The legacy shape remains the default for preexisting partners until they migrate. Once your integration is fully migrated to the modern shape, contact Nmbr support to make it the default behavior for your partner. After that, you can remove the `Prefer` headers from your requests. ### Affected Endpoints The change applies to employee and employer benefit resources wherever they are created or updated: * `POST /employee_benefits` * `PUT /employee_benefits/:id` * `POST /employee_benefits/bulk/create` * `POST /employee_benefits/bulk/update` * `POST /employee_benefits/batch/upsert` * `POST /employer_benefits` * `PUT /employer_benefits/:id` * `POST /employer_benefits/bulk/create` * `POST /employer_benefits/bulk/update` * `POST /employer_benefits/batch/upsert` It also applies to the corresponding read endpoints (`GET /employee_benefits`, `GET /employee_benefits/:id`, `GET /employer_benefits`, `GET /employer_benefits/:id`) and to `employee_benefit` and `employer_benefit` fields expanded in other resources. ### What's Not Changing Benefit line items are unaffected: they never carried a `percent` field. ## Deprecating synchronous mode on bulk endpoints > 🚧 Breaking Change > Bulk endpoints will default to asynchronous mode for all partners in a future release. > Synchronous mode is deprecated. ### Background Bulk create, update, and delete endpoints currently support two modes of operation: **Synchronous mode** (deprecated): * Processes the operation synchronously * Returns HTTP 201 Created, HTTP 200 OK, or HTTP 204 No Content * Returns the created or updated models in the response body **Asynchronous mode**: * Returns HTTP 202 Accepted * Returns an [async task](https://docs.nmbr.co/api-reference/async-tasks/retrieve-an-async-task) in the response body * Processes the operation asynchronously * Returns the created or updated models via the async task result endpoint Synchronous mode is the current default for preexisting partners but will be deprecated in a future release. Asynchronous mode is the default for new partners going forward. For more details on asynchronous bulk operations, see the [Bulk and Batch Operations](https://docs.nmbr.co/api/bulk-and-batch-operations/bulk-line-item-operations) documentation. ### Migrating to Asynchronous Mode To help preexisting partners migrate their integrations, you can force either mode by passing a `Prefer` header with the request: * To force asynchronous mode: `Prefer: deprecate_sync_bulk=true` * To force synchronous mode: `Prefer: deprecate_sync_bulk=false` We recommend migrating to asynchronous mode as soon as possible by passing `Prefer: deprecate_sync_bulk=true` on all bulk requests. Once your integration is fully migrated to asynchronous mode, contact Nmbr support to make this the default behavior for your partner. After that, you can remove the `Prefer` headers from your requests. ### Affected Endpoints Recurrence bulk endpoints: * `POST /allowances/bulk/create` * `POST /allowances/bulk/update` * `POST /allowances/bulk/delete` * `POST /deductions/bulk/create` * `POST /deductions/bulk/update` * `POST /deductions/bulk/delete` * `POST /earnings/bulk/create` * `POST /earnings/bulk/update` * `POST /earnings/bulk/delete` * `POST /employee_benefits/bulk/create` * `POST /employee_benefits/bulk/update` * `POST /employee_benefits/bulk/delete` * `POST /employer_benefits/bulk/create` * `POST /employer_benefits/bulk/update` * `POST /employer_benefits/bulk/delete` * `POST /reimbursements/bulk/create` * `POST /reimbursements/bulk/update` * `POST /reimbursements/bulk/delete` * `POST /pay_rates/bulk/create` * `POST /pay_rates/bulk/update` * `POST /pay_rates/bulk/delete` * `POST /overtime_rates/bulk/create` * `POST /overtime_rates/bulk/update` * `POST /overtime_rates/bulk/delete` Line item bulk endpoints: * `POST /allowance_line_items/bulk/create` * `POST /allowance_line_items/bulk/update` * `POST /allowance_line_items/bulk/delete` * `POST /deduction_line_items/bulk/create` * `POST /deduction_line_items/bulk/update` * `POST /deduction_line_items/bulk/delete` * `POST /earning_line_items/bulk/create` * `POST /earning_line_items/bulk/update` * `POST /earning_line_items/bulk/delete` * `POST /employee_benefit_line_items/bulk/create` * `POST /employee_benefit_line_items/bulk/update` * `POST /employee_benefit_line_items/bulk/delete` * `POST /employer_benefit_line_items/bulk/create` * `POST /employer_benefit_line_items/bulk/update` * `POST /employer_benefit_line_items/bulk/delete` * `POST /reimbursement_line_items/bulk/create` * `POST /reimbursement_line_items/bulk/update` * `POST /reimbursement_line_items/bulk/delete` Other bulk endpoints: * `POST /remittance_account_enrollments/bulk/create` * `POST /remittance_account_enrollments/bulk/delete` * `POST /work_assignments/bulk/create` * `POST /work_assignments/bulk/update` ## Deprecating synchronous execution of batch endpoints > 🚧 Breaking Change > Batch endpoints will execute asynchronously for all partners in a future release. > Synchronous execution is deprecated. ### Background Batch upsert and delete endpoints already return the asynchronous response shape (HTTP 202 Accepted with an [async task](https://docs.nmbr.co/api-reference/async-tasks/retrieve-an-async-task) in the response body). However, for preexisting partners, the operation is currently executed synchronously before returning the response. In a future release, batch endpoints will execute asynchronously for all partners. Asynchronous execution is already the default for new partners going forward. ### Migrating to Asynchronous Execution To help preexisting partners migrate their integrations, you can force either mode by passing a `Prefer` header with the request: * To force asynchronous execution: `Prefer: deprecate_sync_batch=true` * To force synchronous execution: `Prefer: deprecate_sync_batch=false` We recommend migrating to asynchronous execution as soon as possible by passing `Prefer: deprecate_sync_batch=true` on all batch requests. Once your integration is fully migrated to asynchronous execution, contact Nmbr support to make this the default behavior for your partner. After that, you can remove the `Prefer` headers from your requests. ### Affected Endpoints Recurrence batch endpoints: * `POST /allowances/batch/upsert` * `POST /allowances/batch/delete` * `POST /deductions/batch/upsert` * `POST /deductions/batch/delete` * `POST /earnings/batch/upsert` * `POST /earnings/batch/delete` * `POST /employee_benefits/batch/upsert` * `POST /employee_benefits/batch/delete` * `POST /employer_benefits/batch/upsert` * `POST /employer_benefits/batch/delete` * `POST /reimbursements/batch/upsert` * `POST /reimbursements/batch/delete` * `POST /pay_rates/batch/upsert` * `POST /pay_rates/batch/delete` * `POST /overtime_rates/batch/upsert` * `POST /overtime_rates/batch/delete` Line item batch endpoints: * `POST /allowance_line_items/batch/upsert` * `POST /allowance_line_items/batch/delete` * `POST /deduction_line_items/batch/upsert` * `POST /deduction_line_items/batch/delete` * `POST /earning_line_items/batch/upsert` * `POST /earning_line_items/batch/delete` * `POST /employee_benefit_line_items/batch/upsert` * `POST /employee_benefit_line_items/batch/delete` * `POST /employer_benefit_line_items/batch/upsert` * `POST /employer_benefit_line_items/batch/delete` * `POST /reimbursement_line_items/batch/upsert` * `POST /reimbursement_line_items/batch/delete` Other batch endpoints: * `POST /contractors/batch/upsert` * `POST /contractors/batch/delete` * `POST /employees/batch/upsert` * `POST /employees/batch/delete` * `POST /forms/batch/upsert` * `POST /forms/batch/delete` * `POST /tax_properties/batch/upsert` * `POST /tax_properties/batch/delete` * `POST /vacation_pay_settings/batch/upsert` * `POST /vacation_pay_settings/batch/delete` * `POST /work_assignments/batch/upsert` * `POST /work_assignments/batch/delete` ## Fields and features being removed after May 15, 2026 > 🚧 Breaking Change > Several fields and features will be removed after **May 15, 2026**. Most of these are older, legacy fields and features that were repaced with newer ones in 2025, but without a formal deprecation notice. Most partners will already be using the newer fields and features and will not need to make changes as a result. However, it's important to review each change to be sure. ### Removing `employer_ei_multiplier` from business entity resources We're removing the `employer_ei_multiplier` read-only field from business entity resources (`/business_entities`, `/business_entities/:id`, and `business_entity` fields expanded in other resources). We now support having multiple CRA RP account numbers within a single business entity. As part of that feature, we now support managing a reduced EI rate through tax properties on the relevant CRA remittance account. For more information, see the [EI Rate Reduction](https://docs.nmbr.co/guides/canada/ei-rate-reduction) documentation. ### Removing `tax_jurisdiction` from work assignment resources We're removing the `tax_jurisdiction` field from work assignment resources (`/work_assignments`, `/work_assignments/:id`, and `work_assignment` fields expanded in other resources). A work assignment may work in different tax jurisdictions in different pay periods. Having a single `tax_jurisdiction` value prevented tracking the tax jurisdiction over time or scheduling changes to it. Instead of setting `tax_jurisdiction`, manage a work assignment's Province of Employment (POE) through its `ca::province_of_employment` tax properties. ℹ️ We are **not** removing the read-only `current_tax_jurisdiction` field as part of these changes. This field returns the value of the work assignment's current `ca::province_of_employment` tax property for convenience. ### Removing `is_cpp_exempt` and `is_ei_exempt` from work assignment resources We're removing the `is_cpp_exempt`and `is_ei_exempt` fields from work assignment resources (`/work_assignments`, `/work_assignments/:id`, and `work_assignment` fields expanded in other resources). A work assignment may be CPP-exempt or EI-exempt in some pay periods but not others. Having single `is_cpp_exempt` and `is_ei_exempt` values prevented tracking or scheduling changes to CPP-exempt and EI-exempt status over time. Instead of setting `is_cpp_exempt` or `is_ei_exempt`, manage a work assignment's CPP-exempt and EI-exempt statuses through its `ca::cpp_exempt` and `ca::ei_exempt` tax properties. ℹ️ QPP- and QPIP-exempt status is already managed through tax properties. ### Removing `employee_summary.deductions` and `employee_summary.deductions_ytd` from pay stub resources We're removing the `employee_summary.deductions` and `employee_summary.deductions_ytd` fields from pay stub resources (`/pay_stubs`, `/pay_stubs/:id`, and `pay_stub` fields expanded in other resources). These fields are poorly-named. Their names suggest they're the sum of deduction line items on the pay stub (or pay stubs year-to-date), but they're actually the sum of any line item subtracted from the employee's pay, i.e. deduction, employee benefit, and employee statutory withholding line items. You can get the same information from the `employee_summary.subtractions` and `employee_summary.subtractions_ytd` fields respectively. ### Removing support for creating forms identifying owner with `work_assignment_id` We're removing support for creating a form (`POST /forms`) using a `work_assignment_id` field to identify the owner of the form. When we first added support for forms, we only supported work assignment-level forms (e.g. TD1 and TP-1015.3-V), and so only ever needed `work_asignment_id`. Now that we support employee-level forms (e.g. T4 and ROE), we need different identifiers for different forms. Instead of sending a `work_assignment_id` on the request ``` POST /forms { "work_assignment_id": "wrkas_...", ... } ``` send the appropriate value in `owner_id`: ``` POST /forms { "owner_id": "wrkas_...", // work assignment identifier for work assignment-level forms, etc ... } ``` ### Removing `work_assignment` from form resources We're removing the `work_assignment` field from form resources (`/forms`, `/forms/:id`, and `form` fields expanded in other resources). Use the `owner` field to determine the owner of the form. ### Removing support for expanding all line items on a pay stub with `?expand=line_items` We're removing support for expanding all line items on a pay stub in a single `line_items` field using `/pay_stubs?expand=line_items` or `/pay_stub/:id?expand=line_items`. Each type of line item has a unique shape, and adding new types of line items could break consumers who aren't expecting their shapes. Additionally, some use cases only require certain types of line items, and returning all line items is unnecessarily expensive. Instead of using `expand=line_items` to expand the line items, use `expand=_line_items,_line_items,...` for each type of line item you want returned. ### Removing `t4_code` from allowance type resources We're removing the `t4_code` field from allowance type resources (`/allowance_types`, `/allowance_types/:id`, and `allowance_type` fields expanded in other resources). Where an allowance is reported on a T4 isn't a simple 1:1 mapping. This field was always previously returned with the value `null`. The `form_mappings` field contains more nuanced information about how types map to forms. ### Removing `is_taxable`, `is_insurable`, and `is_pensionable` from allowance type resources We're removing the `is_taxable`, `is_insurable`, and `is_pensionable` fields from allowance type resources (`/allowance_types`, `/allowance_types/:id`, and `allowance_type` fields expanded in other resources). Whether or not an allowance type is taxable, insurable, or pensionable isn't a simple boolean value; it varies by jurisdiction. We've replaced these fields with a new [Line Item Type Features](https://docs.nmbr.co/guides/payroll-fundamentals/line-item-type-features) system that will return more nuanced information about line item types in each jurisdiction we support. ### Removing `t4_code` from deduction type resources We're removing the `t4_code` field from deduction type resources (`/deduction_types`, `/deduction_types/:id`, and `deduction_type` fields expanded in other resources). Where a deduction is reported on a T4 isn't a simple 1:1 mapping. This field was always previously returned with the value `null`. The `form_mappings` field contains more nuanced information about how types map to forms. ### Removing `t4_code` from reimbursement type resources We're removing the `t4_code` field from reimbursement type resources (`/reimbursement_types`, `/reimbursement_types/:id`, and `reimbursement_type` fields expanded in other resources). Where a reimbursement is reported on a T4 isn't a simple 1:1 mapping. This field was always previously returned with the value `null`. The `form_mappings` field contains more nuanced information about how types map to forms. ### Removing the `is_taxable`, `is_insurable`, and `is_pensionable` from reimbursement type resources We're removing the `is_taxable`, `is_insurable`, and `is_pensionable` fields from reimbursement type resources (`/reimbursement_types`, `/reimbursement_types/:id`, and `reimbursement_type` fields expanded in other resources). Whether or not a reimbursement type is taxable, insurable, or pensionable isn't a simple boolean value; it varies by jurisdiction. We've replaced these fields with a new [Line Item Type Features](https://docs.nmbr.co/guides/payroll-fundamentals/line-item-type-features) system that will return more nuanced information about line item types in each jurisdiction we support. ### Removing journal entry line item report We're removing the journal entry *line item* report (`POST /reports/journal-entry-line-item`). It has been replaced by the [Journal Entry Report](https://docs.nmbr.co/api-reference/reports/create-payroll-register-report). ### Removing amount\_override from line item resources We're removing the `amount_override` field from all line item resources: * `/allowance_line_items/:id` * `/deduction_line_items/:id` * `/earning_line_items/:id` * `/employer_statutory_withholding_line_items/:id` * `/reimbursement_line_items/:id` * `/statutory_withholding_line_items/:id` These fields were for backward-compatibility during the transition from `amount` and `amount_override` to `managed_amount`, `custom_amount`, and `amount` in early 2025. Use the `custom_amount` field instead. ## name Read-Only amount and hours Properties on Line Items > 🚧 Breaking Change > The `amount` and `hours` properties on Line Items will be read-only as of **March 1, 2026**. ## Read-Only `amount` and `hours` Properties on Line items ### Introduction In Nmbr, each type of line item has 3 "amount" properties: * `managed_amount`: The managed amount for the line item. The value is either calculated by the system (e.g. statutory holiday pay or vacation pay payout) or configured on the line item's recurrence (e.g. a recurring allowance's `amount`). This property is read-only. * `custom_amount`: The custom amount for the line item. * `amount`: The final amount for the line item. This is the amount that will be paid, deducted, withheld, etc. The value will be `custom_amount`, if set, and `managed_amount` otherwise. Similarly, the earning line item type has 3 "hours" properties: * `managed_hours`: The managed hours for the line item. This amount is the default number of hours on the line item's Pay Rate. This property is read-only. * `custom_hours`: The custom hours for the line item. `custom_hours` can be used to prorate the dollar `amount` on salary line items with a Pay Rate. * `hours`: The final hours for the line item. The value will be `custom_hours`, if set, and `managed_hours` otherwise. Currently, the `amount` and `hours` properties are read/write. If you create or update a line item with an `amount` or `hours` value, the line item's `custom_amount` or `custom_hours` values will be set. ### What's Changing On March 1, 2026 we will be changing the `amount` and `hours` properties to be read-only. If you create or update a line item with `amount` or `hours` values, these values will be ignored. If your application sends `amount` or `hours` properties in requests to create or update line items, you will need to rename `amount` to `custom_amount` and `hours` to `custom_hours` in requests. For example, if you make the following request to create an earning line item `POST /earning_line_items` ``` { ... "amount": 500, "hours": 10, ... } ``` you would need to rename the properties as follows `POST /earning_line_items` ``` { ... "custom_amount": 500, "custom_hours": 10, ... } ``` ### What's Not Changing We will continue sending the computed `amount` and `hours` values in responses. Your application can continue to rely on these values. `GET /earning_line_items/ernli_01KBG99GP45784S1PVZTAGFE6X` ``` { ... "managed_amount": 1000, "managed_hours": 20, ... "custom_amount": 500, "custom_hours": 10, ... "amount": 500, // computed from managed_amount and custom_amount "hours": 10, // computed from managed_hours and custom_hours ... } ``` ## name Property Required on Business Presets > 🚧 Breaking Change > The `name` property on Business Presets will be required as of **November 15th, 2025**. ## `name` Property Required on Business Presets Business Presets currently require a value for *either* the `title` property or the `name` property. * `title` is copied to recurrences (pay rates, allowances, employee and employer benefits, deductions, and reimbursements) and line items, and used as their `title`. * `name` is used to identify the preset in the component or portal, or when grouping line items by preset on pay stubs or reports. If a Business Preset doesn't have a `name`, we currently fall back on `title`. We will be making the `name` property required as of November 15th, 2025 and removing the logic that currently falls back to `title`. In order to create new Business Presets, you will need to supply a value for `name`. The `title` property will continue to be optional. ## Business Entity-level templates deprecated > 🚧 **Breaking Change** > Business Entity-level templates for Allowances, Benefits, Deductions, and Reimbursements have been deprecated and will be removed on **November 15, 2025**. Please migrate to the new [Business Presets](/guides/advanced/presets) feature. Legacy endpoints will continue to function until this date but will not receive updates or bug fixes. ## Deprecation of Business Entity-Level Templates for Allowances, Benefits, Deductions, and Reimbursements Nmbr previously supported defining templates for Allowances, Benefits, Deductions, and Reimbursements at the Business Entity level. As part of improving our API and providing a more consistent experience, we are replacing this feature with the new [Business Presets](/guides/advanced/presets) feature, which supports a larger set of use cases with fewer endpoints. ## Deprecated Endpoints The following endpoints are now deprecated and have been replaced by the new Business Presets endpoints: * `/business_entity_allowances` * `/business_entity_benefits` * `/business_entity_deductions` * `/business_entity_reimbursements` # Migration ## Data You do NOT need to perform a data migration from legacy templates to Business Presets. When Business Presets were released, legacy templates were migrated to Business Presets of the appropriate `type`. For example, every legacy template for Allowances was migrated to a Business Preset of type `allowance`. To maintain backward compatibility, the APIs for these features were changed to manage Business Presets of the appropriate `type`. For example, creating/updating/deleting a Business Preset of type `allowance` will *appear* to create/update/delete a legacy template for Allowances, and vice versa. However, behind the scenes there is actually only one record in the Nmbr system: the Business Preset. During this migration, the ULIDs for legacy templates were retained as the ULID for the corresponding Business Preset, so partners will **not** need to store two ULID values (legacy template ULID and Business Preset ULID) or map between them. ## API You **DO** need to perform a code migration to change any code that is currently calling the legacy template APIs to instead call the Business Presets APIs. ### Allowances Change any code calling the `/business_entity_allowances` endpoints with the property `"allowance_type": "T"` to instead call the corresponding `/business_presets` endpoints with the properties `"type": "allowance"` and `"subtype": "T"`. For example, if you're working with taxable meals allowances, `"allowance_type": "meals_taxable"` will become `"type": "allowance"` and `"subtype": "meals_taxable"`. As mentioned in the data section above, you can continue to use the ULIDs for legacy templates. \| Action | Old Endpoint | New Endpoint | |||| \| | `name` | New required property. All Business Presets must have a name. The name is used when listing Business Presets and when grouping line items by Business Preset. | \| | `type` | New required property. For allowances, the type is always `allowance`. | \| `allowance_type` | `subtype` | Renamed. | \| `business_entity_id` | `business_entity_id` | Unchanged. | \| `title` | `title` | Unchanged. | ### Benefits Since Business Presets were released, Benefits were split into separate Employer Benefits and Employee Benefits. For Employer Benefits, change any code calling the `/business_entity_benefits` endpoints with the property `"benefit_type": "T"` to instead call the corresponding `/business_presets` endpoints with the properties `"type": "employer_benefit"` and `"subtype": "T"`. \| Action | Old Endpoint | New Endpoint | |||| \| Create | `POST /business_entity_benefits` with body `{ "benefit_type": "T", ... }` | `POST /business_presets` with body `{ "type": "employee_benefit", "subtype": "T", ... }` | \| List | `GET /business_entity_benefits` | `GET /business_presets?type=employee_benefit` | \| Retrieve | `GET /business_entity_benefits/:ulid` | `GET /business_presets/:ulid` | \| Update | `PUT /business_entity_benefits/:ulid` | `PUT /business_presets/:ulid` | \| Delete | `DELETE /business_entity_benefits/:ulid` | `DELETE /business_presets/:ulid` | The legacy benefit template properties map to the Business Presets properties as follows: \| Old Property | New Property | Notes | |||| \| Create | `POST /business_entity_deductions` with body `{ "deduction_type": "T", ... }` | `POST /business_presets` with body `{ "type": "deduction", "subtype": "T", ... }` | \| List | `GET /business_entity_deductions` | `GET /business_presets?type=deduction` | \| Retrieve | `GET /business_entity_deductions/:ulid` | `GET /business_presets/:ulid` | \| Update | `PUT /business_entity_deductions/:ulid` | `PUT /business_presets/:ulid` | \| Delete | `DELETE /business_entity_deductions/:ulid` | `DELETE /business_presets/:ulid` | The legacy deduction template properties map to the Business Presets properties as follows: \| Old Property | New Property | Notes | |||| \| Create | `POST /business_entity_reimbursements` with body `{ "reimbursement_type": "T", ... }` | `POST /business_presets` with body `{ "type": "reimbursement", "subtype": "T", ... }` | \| List | `GET /business_entity_reimbursements` | `GET /business_presets?type=reimbursement` | \| Retrieve | `GET /business_entity_reimbursements/:ulid` | `GET /business_presets/:ulid` | \| Update | `PUT /business_entity_reimbursements/:ulid` | `PUT /business_presets/:ulid` | \| Delete | `DELETE /business_entity_reimbursements/:ulid` | `DELETE /business_presets/:ulid` | The legacy reimbursement template properties map to the Business Presets properties as follows: \| Old Property | New Property | Notes | ||---| \| | `name` | New required property. All Business Presets must have a name. The name is used when listing Business Presets and when grouping line items by Business Preset. | \| | `type` | New required property. For reimbursements, the type is always `reimbursement`. | \| `deduction_type` | `subtype` | Renamed. | \| `business_entity_id` | `business_entity_id` | Unchanged. | \| `title` | `title` | Unchanged. | ## Deprecation of Legacy Benefits API > 🚧 **Breaking Change**\ > The legacy Benefits API has been deprecated and will be removed on **August 31, 2025**.\ > Please use the new Benefits API endpoints for all benefit-related operations. Legacy endpoints will continue to function until this date but will not receive updates or bug fixes. ## Deprecation of Legacy Benefits API As part of improving our API and providing a more consistent experience, we are deprecating the legacy Benefits endpoints. We have split the functionality into two distinct sets of API endpoints: one for employers and one for employees. This allows us to better align the Benefits functionality with our existing API structure. All existing data has been migrated to the new endpoints, and you can continue to access your employee and employer benefits data without interruption. All existing Benefit and Benefit Line Item ULIDs have been preserved on the corresponding Employee Benefit and Employee Benefit Line Item records. More information can be found in the [Configuring Benefits documentation](/guides/payroll-fundamentals/configuring-benefits). As well as providing a more consistent API experience, these changes are required to offer improved functionality for reporting and GL code mapping. ## Legacy Benefits API Deprecation The following endpoints are now deprecated and have been replaced by the new Employee and Employer Benefits API endpoints: * `/benefits` β†’ replaced by: * `/employee_benefits` * `/employer_benefits` * `/benefit_line_items` β†’ replaced by: * `/employee_benefit_line_items` * `/employer_benefit_line_items` * `/benefit_types` β†’ replaced by: * `/employee_benefit_types` * `/employer_benefit_types` ## Benefit Types Previously, a single `benefit_type` was used to categorize benefits. This did not correctly represent benefits as they are used in the real world. Some benefits are contributed to by both the employer and employee, while others are only contributed to by one party. This ambiguity made accurate reporting and accounting more difficult. To address this, we have introduced two new benefit types: `employee_benefit_type` and `employer_benefit_type`. The two benefit types now contain different values, reflecting the distinct contributions made by employees and employers. For example, `pension_rrsp` may appear in both `employee_benefit_type` and `employer_benefit_type`, whereas `gift_near_cash` will only appear in `employer_benefit_type`. These changes not only provide a more consistent API experience but also enable improved reporting and GL code mapping. ## Updates to Line Item Type Filters > 🚧 **Breaking Change** > Type filters in Line Item listing endpoints have been replaced with `include_types`. > The deprecated filters listed below will be removed on **June 30, 2025**. ## Renamed Type Filters for Line Item Listings The following query parameters have been renamed to `include_types` for consistency across line item listing endpoints: * `allowance_type` β†’ `include_types` ([Allowances](/api-reference/allowances/list-allowances)) * `benefit_type` β†’ `include_types` ([Benefits](/api-reference/employee-benefits/list-employee-benefits)) * `deduction_type` β†’ `include_types` ([Deductions](/api-reference/deductions/list-deductions)) * `earning_type` β†’ `include_types` ([Earnings](/api-reference/earnings/list-earnings)) * `employer_statutory_withholding_type` β†’ `include_types` ([Employer Statutory Withholdings](/api-reference/employer-statutory-withholding-line-items/list-employer-statutory-withholding-line-items)) * `reimbursement_type` β†’ `include_types` ([Reimbursements](/api-reference/reimbursements/list-reimbursements)) * `statutory_withholding_type` β†’ `include_types` ([Statutory Withholdings](/api-reference/statutory-withholding-line-items/list-statutory-withholding-line-items)) ## New Filtering Options All line item listing endpoints now support both: * **`include_types`**: Return only items matching one or more specified types. *Example*: Retrieve only `wage` and `overtime` earnings. * **`exclude_types`**: Exclude items of one or more specified types from the results. *Example*: Omit `union_dues` from deduction results. *** These changes promote consistency and improve filtering flexibility across the API. ## Additional Validation on Date Fields > 🚧 Breaking Change > Additional validation will be performed on date fields as of **May 1st, 2025**. ## Additional Validation on Date Fields Our API accepts and returns date-related fields following the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard: * `date` fields are formatted `YYYY-MM-DD` without a time component (e.g. `2023-01-01`) * `date-time` fields are formatted `YYYY-MM-DDThh:mm:ss.sssZ` (e.g. `2023-01-01T06:30:00.000000Z`) However, some endpoints are not currently validating the format of some `date` fields, and are accepting the `date-time` format or other formats. We will be introducing validation on these fields beginning May 1, 2025, and accepting only the `date` format after that. The following key fields have been identified as changing: * When creating or updating [employees](/api-reference/employees/create-an-employee), the `date_of_birth` field must be formatted `YYYY-MM-DD`. * When creating or updating [allowances](/api-reference/allowances/create-an-allowance), [benefits](/api-reference/employee-benefits/create-an-employee-benefit), [deductions](/api-reference/deductions/create-a-deduction), [reimbursements](/api-reference/reimbursements/create-a-reimbursement), or [pay rates](/api-reference/pay-rates/create-a-pay-rate), the `effective_from` and `effective_to` fields must be formatted `YYYY-MM-DD`. * When creating or updating [pay schedules](/api-reference/pay-schedules/create-a-pay-schedule), the `anchor_pay_date` and `anchor_end_of_pay_period` fields must be formatted `YYYY-MM-DD`. * When [terminating work assignments](/api-reference/work-assignments/terminate-a-work-assignment), the `effective_date` field must be formatted `YYYY-MM-DD`. * When filtering reports by pay date, the `pay_date_from` and `pay_date_to` fields must be formatted `YYYY-MM-DD`. However, this change will apply to **all** fields documented as `date` in our documentation. Please ensure that `date` fields are properly formatted. ## amount Required on Reimbursements > 🚧 Breaking Change > `amount` field required on reimbursements as of **May 30th, 2025**. ## `amount` Required on Reimbursements When [creating reimbursements](/api-reference/reimbursements/create-a-reimbursement), the `amount` field is not currently a required field. We will be making the `amount` field a required field beginning May 30, 2025, and requiring a value for the field after that. Please ensure the `amount` field is supplied when creating reimbursements. ## Deprecating Vacation Pay on Pay Rates > 🚧 Deprecation Notice > Vacation Pay on Pay Rates is being deprecated and will be removed on **May 15th, 2025**. ## Deprecating Vacation Pay on Pay Rates As part of improvements to functionality for Vacation Pay, we have deprecated the Vacation Pay attributes on the Pay Rate entity. * `vacation_pay_percentage` - this attribute is deprecated and has been removed. * `vacation_pay_method` - this attribute is deprecated and has been removed. These changes will take effect on May 15th, 2025. ## Migrating to Vacation Pay Settings To manage the vacation pay percentage and payout methods for a Work Assignment, you can use the `vacation_pay_settings` endpoint. This entity will allow you to set the percentage, the effective dates, and method of vacation pay for a specific Work Assignment. All eligible earning line items will have vacation pay calculated based on the active Vacation Pay Setting and the Province of Employment for the Work Assignment. To read more, please see the [Vacation Pay Guide](/guides/payroll-fundamentals/vacation-pay). ## Standardizing Historical Payroll Terminology We've standardized on the term "historical payroll" for payrolls run with a different provider in the current calendar year. To create a historical payroll, a post request should use the `type: historical`. View [docs](/guides/advanced/historical-payrolls). ## Updates to Future PayStub Line Items **Enhanced Line Item Generation:** We’ve refined the generation process for recurring line items on future Pay Stubs. Now, line items for recurring Earnings, Benefits, Reimbursements, Allowances, and Deductions will automatically populate once the preceding payroll changes status to paid. This ensures that your upcoming Pay Stubs reflect the most current and accurate information. ## Changes to Validation on Pay Rates **Required `expected_hours_per_week` Field**: To improve the accuracy of Statutory Withholdings for off-cycle Payrolls, the `expected_hours_per_week field` is now mandatory when creating a new Pay Rate. This update helps minimizing discrepancies and potential errors in payroll processing. # Component Source: https://docs.nmbr.co/changelog/component Product updates and announcements # Portal Source: https://docs.nmbr.co/changelog/portal Product updates and announcements # Customization Source: https://docs.nmbr.co/components/customization Hide or disable parts of the Nmbr Component UI by passing settings during initialization. ## Settings When initializing the Nmbr Component, you can pass additional configurations through via the `settings` property, allowing you to hide and disable parts of the UI: ```html payroll.html theme={null} ``` ### Available Settings All properties are optional. These settings are meant to change the UX of the component, and *do not* prevent the user from, **at the API level**, creating, reading, updating or deleting the related resource(s). For example, if the Employee "Bank Accounts" section is hidden, the user will not be able to *view* the Bank Accounts tab or access any of its functionality through the Nmbr Component. *However*, if your signing server does not disallow it, the user *could* still create, read, update, or delete a bank account by accessing the API directly. The full settings payload is shown below: ```json theme={null} { "padEnabled": true, "disablePayrollApproveButton": false, "hideNavigationMenu": false, "hideBusinessSelector": false, "hideCompanyHeader": false, "outerPaddingFactor": 4, "language": "en-CA", "showROEs": false, "showTags": false, "hidePayroll": false, "hidePayrollPayRates": false, "createFromPresetsOnly": false, "showHistoricalPayroll": false, "showCorrectionPayroll": false, "showPayrollAdjustments": false, "hideReports": false, "hideYearEndTaxPackages": false, "employeeTabs": { "hideDetails": false, "hideEmployeePersonalDetailsSection": false, "hideEmployeeIdentificationDetailsSection": false, "hideBankAccount": false, "hideBenefits": false, "hideAllowances": false, "hideDeductions": false, "hideReimbursements": false, "hidePayRates": false, "showOtherEarnings": false, "hideVacationPay": false, "hidePayStubs": false, "hideTaxForms": false, "hideTaxImplications": false, "hideTaxDetails": false, "hideWorkersCompensation": false, "hideCreateEmployeeButton": false, "showStatHolidayPay": false, "showPayScheduleAddRemove": false, "showTaxOverrides": false, "showProfile": false, "profile": { "hidePayRates": false } }, "contractorTabs": { "hideDetails": false, "hideBankAccount": false, "hidePaymentFrequency": false, "hideReceipts": false, "showEarnings": false }, "businessSettings": { "hideDetails": false, "hideBankAccounts": false, "hideTaxAccounts": false, "showRemittanceAccounts": false, "allowAdditionalTaxAccounts": false, "hidePaySchedules": false, "hidePayRunConfig": false, "hideEmployees": false, "hideContractors": false, "hideCreateAnotherBusinessButton": false, "hideVacationPay": false, "hideWorkersCompensation": false, "hidePayrollItems": false, "showGlCodes": false, "hideEmploymentInsurance": false, "hideCreateAnotherPayScheduleButton": false, "hideEpt": false, "showIntegrations": false, "showPreviewModeBanner": false, "allowOutsideCanadaBEs": false } } ``` #### General When `true`, the PAD agreement will be shown in the "Bank Account" tab of the Business Settings, both when viewing and creating a bank account. When creating a bank account, the user will need to review and agree to the PAD agreement. Disables the "Approve" button on the Payroll Approve step. A number greater than or equal to 0. Applied as the multiplier of the scaling factor (8px) to determine the outer padding around the component. For example, a value of `2` results in 16px of outer padding. The language to use in the component. Accepts `en-CA` or `fr-CA`. Hides the built-in navigation menu. Useful when combined with [deep linking](/components/deep-linking) to build your own navigation experience β€” you can use `goto()` to control which page the component displays while hiding the default navigation entirely. Shows the "ROEs" tab for both the Employee Section and the Business Settings. Surfaces tag configuration at the business level, tag assignment at the employee level, and tag allocations across payroll line items. See [Tagging & Journal Entry Tracking](/guides/accounting/tagging). Hide the "Pay Rates" column on the Run Payroll screens. When `true`, line items and recurring employee benefits, allowances, and reimbursements can only be created from pre-existing presets and cannot be created from scratch. Shows the "Historical" tab in the payroll dashboard. Shows the "Correction" tab in the payroll dashboard. Show "Adjustments" for Statutory Withholdings. Hide the "Payroll" section, including the Run Payroll screens and the payroll dashboard. Hide the business selector. Use this when the Component is scoped to a single business and switching businesses should not be available. Hide the company name header shown above the navigation on the account-wide views (Employees, Contractors, and ROEs). The navigation and breadcrumbs remain. Hide the "Reports" section. Hide the "Year-End Tax Packages" section. #### Employee Tabs If all of the tabs in `employeeTabs` are hidden, the employee table will still show all employees, but you won't be able to see their details. Hide the "Details" tab in the Employee Section. When hidden, the "Create Employee" button is also hidden. Hide the "Personal Details" section in the "Details" tab in the Employee Section. Hide the "Identification Details" section in the "Details" tab in the Employee Section. Hide the "Bank Account" tab in the Employee Section. Hide the "Benefits" tab in the Employee Section. Hide the "Allowances" tab in the Employee Section. Hide the "Deductions" tab in the Employee Section. Hide the "Reimbursements" tab in the Employee Section. Hide the "Pay Rates" tab in the Employee Section. Show the "Other Earnings" tab in the Employee Section. Hide the "Vacation Pay" tab in the Employee Section. Hide the "Pay Stubs" tab in the Employee Section. Hide the "Tax Forms" tab in the Employee Section. Hide the "Tax Implications" tab in the Employee Section. Hide the "Tax Details" tab in the Employee Section. When hidden, the "Overrides" table controlled by `showTaxOverrides` is also hidden. Hide the "Workers' Comp" tab in the Employee Section. Hide the "Create Employee" button in the Employee Section. Shows the "Stat Holiday Pay" tab in the Employee Section. Shows the `...` menu in the "Employee" header where the employee can be added to/removed from a "Pay Schedule". Shows the "Overrides" table in the "Tax Details" tab in the Employee Section. Shows the read-only "Profile" tab in the Employee Section. The "Profile" tab consolidates the employee's details, bank account, and pay rates into a single display-only view. Hide the "Pay Rates" section in the "Profile" tab. Only applies when `showProfile` is `true`. #### Contractor Tabs If all of the tabs in `contractorTabs` are hidden, the table will still show all contractors, but you won't be able to see their details. Hide the "Details" tab in the Contractor Section. When hidden, the "Create Contractor" button is also hidden. Hide the "Bank Account" tab in the Contractor Section. Hide the "Payment Frequency" tab in the Contractor Section. When hidden, the `...` menu for removing the contractor from a "Payment Frequency" is also hidden. Hide the "Receipts" tab in the Contractor Section. Show the "Earnings" tab in the Contractor Section. #### Business Settings If all of the tabs in `businessSettings` are hidden, the "Business Settings" option will not appear in the main navigation menu. Hide the "Details" tab in the Business Settings. Hide the "Bank Accounts" tab in the Business Settings. Hide the "Tax Accounts" tab in the Business Settings. Show the "Remittance Accounts" tab in the Business Settings. When `true`, the user can create more than one Remittance Account of the same provider type (e.g. multiple CRA `RP` accounts, multiple RQ `RS` accounts) for a Business Entity. Useful for businesses that operate multiple program accounts with the CRA β€” for example, separate divisions that each remit under their own `RP` number. See [Tax Agency Configuration](/guides/payroll-fundamentals/tax-agency-configuration) for details on how multi-account enrollments work. Hide the "Pay Schedules" tab in the Business Settings. Hide the "Pay Run Configuration" settings in the Business Settings. Hide the "Employees" tab in the Business Settings. When hidden, the "Edit Employee Details" option is also hidden from the `...` menu on the Payroll Earnings and Review screens. Hide the "Contractors" tab in the Business Settings. Hide the "Create Another" button in the "Details" tab in the Business Settings. Hide the "Vacation Pay" tab in the Business Settings. Hide the "Workers' Comp" tab in the Business Settings. Hide the "Payroll Items" tab in the Business Settings. **Deprecated.** Use `businessSettings.hidePayrollItems` instead. Show the "GL Codes" tab in the Business Settings. Hide the "EI Rates" tab in the Business Settings. **Deprecated.** The "Reports" tab is no longer in the Business Settings. Use the top-level `hideReports` setting instead. Hide the "Create Another" button on the "Pay Schedules" tab in the Business Settings. Hide the "EPT" tab in the Business Settings. Formerly `businessSettings.hideEht`. Show the "Integrations" tab in the Business Settings. Show the "Preview Mode" banner when a business is in preview mode. When `true`, allow creating business entities located outside Canada. # Deep Linking Source: https://docs.nmbr.co/components/deep-linking Navigate users directly to specific pages within the Nmbr Component. Deep linking allows you to programmatically navigate users to specific pages within the Nmbr Component β€” for example, opening directly to an employee profile or a specific payroll run. This lets you build your own navigation experiences around the component without needing to know its internal route structure. ## How It Works Instead of exposing internal route paths (which can change), the component provides a set of **named destinations** β€” stable, semantic identifiers like `employee_profile` or `payroll_list`. You reference these destinations by name, and the component handles routing internally. Deep linking controls where the user **starts** or **navigates to**. It does not hide any pages or restrict navigation β€” all tabs and pages remain accessible. Think of it as "start here", not "only show this". ## Destinations The following destinations are available: | Destination | Required Params | Description | | ----------------------- | --------------- | ------------------------------------------------- | | `employee_list` | β€” | Employee directory | | `employee_profile` | `employeeId` | A specific employee's profile | | `contractor_list` | β€” | Contractor directory | | `contractor_profile` | `contractorId` | A specific contractor's profile | | `payroll_list` | β€” | Payroll runs list for the current business entity | | `payroll` | `payrollId` | A specific payroll run | | `business_settings` | β€” | Business entity settings | | `year_end_tax_packages` | β€” | Year-end tax packages | | `reports` | β€” | Reports page | | `roes` | β€” | Records of Employment | Destinations that require a `businessEntityId` internally (like `payroll_list`, `business_settings`, etc.) resolve it automatically from the user's current context β€” you do not need to provide it. ## Usage There are two ways to deep link: at **load time** (when the component first mounts) and **after load** (navigate an already-loaded component). ### Navigate on Load Pass a `destination` in the options when calling `load()`. The component will navigate to that page as soon as it is ready, avoiding a flash of the default landing page. ```javascript theme={null} const host = ComponentsHost.initialize({ companyId: 'your-company-id', partnerId: 'your-partner-id', signingUrl: '/sign_nmbr_request', }); // Navigate to the employee list on load const portal = host.load(container, { destination: { name: 'employee_list' }, }); // Navigate to a specific employee profile on load const portal = host.load(container, { destination: { name: 'employee_profile', params: { employeeId: 'emp_01ABC123' }, }, }); ``` ### Navigate After Load Use the `goto()` method on a loaded portal frame to navigate at any time. This is useful when your app has its own navigation (e.g., sidebar links, buttons) that should control what the component displays. ```javascript theme={null} const portal = host.load(container); // Later, in response to user action in your app: await portal.goto('employee_profile', { employeeId: 'emp_01ABC123' }); // Navigate to a page without params: await portal.goto('payroll_list'); ``` `goto()` returns a promise that resolves once the navigation message has been sent to the component. You can safely call `goto()` before or after the component is ready β€” it will wait for the connection to be established. ## Works with Customization Settings Deep linking does not hide anything on its own β€” but the component continues to obey all [customization settings](/components/customization) you have configured. This means you can combine deep linking with settings like `hideNavigationMenu`, tab visibility, and other options to fully tailor the experience. For example, if you set `hideNavigationMenu: true`, the component's built-in navigation menu is hidden. You can then use `goto()` to build your own navigation that controls which page the component displays. The component will still respect any other customization settings you have in place (hidden tabs, disabled buttons, etc.). ```javascript theme={null} const host = ComponentsHost.initialize({ companyId: 'your-company-id', partnerId: 'your-partner-id', signingUrl: '/sign_nmbr_request', settings: { hideNavigationMenu: true, // hide the built-in navigation menu employeeTabs: { hideBenefits: true, // still respected alongside deep linking }, }, }); const portal = host.load(container, { destination: { name: 'employee_list' }, }); // Your app now fully controls navigation via goto() ``` ## Example: Building a Custom Navigation A common pattern is to build your own sidebar or tab navigation that controls which page the component displays: ```html theme={null}
``` ## Important Notes * **Deep linking does not hide anything.** Users can still navigate freely within the component after landing on the destination. It only controls the starting point. * **Destination names are a stable API.** Unlike internal route paths, destination names will not change without a deprecation notice. You can safely hard-code them. * **Business entity context is automatic.** For destinations that are scoped to a business entity (like `payroll_list` or `business_settings`), the component resolves the business entity from the user's current context. You do not need to pass a `businessEntityId`. * **Invalid destinations are handled gracefully.** If an unrecognized destination name is passed, the component falls back to the default landing page. # Events Source: https://docs.nmbr.co/components/events The Nmbr Component broadcasts events that your app can listen for The Nmbr Component currently broadcasts a limited number of lifecycle/domain events related to payroll and user navigation. Your application can listen for and react to these events in order to add your own UX experiences within your app. ## Events | Name | Description | Data | | ---------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | `payroll-review` | Broadcasted when the user reaches the "review" step of the payroll run experience. | `{ data: { id: string}}`, where `id` corresponds to the ID of the payroll currently being reviewed by the user | ## API To listen and react to events, you need to use the `on` and `off` API available on `window.nmbr`. The first argument to `on`/`off` must be the name of the event you want to listen for, and the second argument must be a function that will execute when the event is broadcasted. ```typescript theme={null} function alertUser(event, data) { window.alert( `CALLBACK 1: payroll-review event fired with id: ${data.data.id}`, ); } // To subscribe to events via `nmbr.on`: window.nmbr.on('payroll-review', alertUser); // To unsubscribe from events via `nmbr.off`: window.nmbr.off('payroll-review', alertUser); ``` # Fullscreen Source: https://docs.nmbr.co/components/fullscreen Expand the Nmbr Component to fill the browser viewport. The Nmbr Component renders inside a container element you control, and its iframe sizes itself to 100% of that container. Fullscreen is therefore handled on your side: expand the container and the component grows to match. No additional configuration is required from Nmbr. ## Using a CSS overlay The simplest approach is a fixed-position overlay. Add a class that pins the container to every edge of the viewport, then toggle it on demand. ```css theme={null} #nmbr-container.fullscreen { position: fixed; inset: 0; z-index: 9999; } ``` ```javascript theme={null} const container = document.querySelector('#nmbr-container'); const fullscreenButton = document.querySelector('#fullscreen-button'); fullscreenButton.addEventListener('click', () => { container.classList.toggle('fullscreen'); }); ``` Because the overlay covers your own application chrome (including the button that toggled it), render an exit control that stays visible in fullscreen. Position it above the overlay, and toggle its visibility together with the overlay: ```css theme={null} #exit-fullscreen { position: fixed; top: 1rem; right: 1rem; z-index: 10000; } ``` ```javascript theme={null} const container = document.querySelector('#nmbr-container'); const fullscreenButton = document.querySelector('#fullscreen-button'); const exitButton = document.querySelector('#exit-fullscreen'); function setFullscreen(on) { container.classList.toggle('fullscreen', on); exitButton.hidden = !on; } fullscreenButton.addEventListener('click', () => { setFullscreen(!container.classList.contains('fullscreen')); }); exitButton.addEventListener('click', () => setFullscreen(false)); ``` Don't rely on the Escape key as the only way out. Once the user interacts with the component, keyboard focus moves into its iframe and key events no longer reach your page, so an `Escape` listener on the host document stops firing. A visible exit control always works because it lives in your page, above the overlay. You can still add `Escape` as a convenience: ```javascript theme={null} document.addEventListener('keydown', (event) => { if (event.key === 'Escape') { setFullscreen(false); } }); ``` The component renders its modals and notifications at a very high stacking order, so keep your overlay and its exit control below them. The values shown above are safe; a much larger `z-index` can cause the component's own dialogs to appear behind your overlay. ## Native Fullscreen API For true, OS-level fullscreen that also hides the browser's own chrome, call the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API) on the container instead: ```javascript theme={null} const container = document.querySelector('#nmbr-container'); // Must be triggered by a user gesture, such as a click container.requestFullscreen(); // Exit fullscreen document.exitFullscreen(); ``` The CSS overlay is recommended for most integrations: it keeps the browser chrome visible, does not require a user gesture, and gives you full control over the transition. # Getting Started Source: https://docs.nmbr.co/components/getting-started The fastest way to ship a fully-featured payroll system in your app. The Nmbr Component offers a fully-featured payroll suite in a lightweight integration. It takes less than an hour for a single developer to add payroll features to any app using our embeddable payroll module, designed and built by our in-house experts to work seamlessly with your data in any environment. To get started, you will need the following: * A Partner ID, API Key, and API Secret from our [Portal](/portal/working-with-the-nmbr-dashboard). * The ability to add a server-side endpoint in your app's API * The ability to add or change HTML pages in your app's UI ## How it works You will be adding a javascript ` ``` #### Types The type information for the configuration object passed to `nmbr.initialize` is as follows: ```ts theme={null} type InitializationConfig = { signingUrl?: string | never; // A `signingUrl` must be provided if the `sign` function is not provided sign?: (message: string) => Promise | never; // A `sign` function must be provided if the `signingUrl` is not provided companyId: string; // The company ID to load the component for partnerId: string; // Your partner ID sandbox?: boolean; theme?: CustomTheme; // See Theming > Type Information settings?: Settings; // See Customization > Settings > Available Settings }; ``` For more information on the `theme` types, see the [Theming page](/components/theming#type-information) For more information on the `settings` types, see the [Customization page](/components/customization#available-settings) ### Using Vite If you're using Vite, the importmap pattern won't work. In dev mode, Vite tries to resolve package-name imports like `@nmbrco/components` from your local `node_modules` folder before the browser sees the importmap. Since `@nmbrco/components` is loaded from Nmbr's CDN rather than installed as an npm package, Vite returns a 404. If you're using Vite, use this dynamic import instead of the importmap install and static import shown above. The full URL points directly at Nmbr's CDN, so Vite doesn't try the node\_modules lookup: ```html payroll.html theme={null} ``` ### Load the Run Payroll component Once your `host.js` script is initialized, you may embed Nmbr's Run Payroll component into any element on your page. ```html payroll.html theme={null}
``` ## 3 - Test your page At this point, you have finished writing all code required to set up Nmbr Components. Let's see it in action! ### Load the payroll page Start by loading the page you set up in Step 2; you should see the embedded iframe start loading in your container. New companies will always start at the Company Setup screen; once they have completed setup the component will default to the Payroll Dashboard. ### Run a payroll in sandbox Once you've confirmed the component is loading, it is time to submit data. To simulate payroll before you go live, import the sandbox version of the scripts and provide the additional option `sandbox: true` for Nmbr Components. (You may also need to provide different partner credentials configured for the sandbox environment). ```html theme={null} ``` ```typescript theme={null} const components = nmbr.initialize({ // ... sandbox: true, }); ``` ## Congratulations! You have successfully embedded Nmbr Components in your app. Consider next how else to customize your integration: * Mirror business, employee, and other data to Nmbr to pre-fill payroll fields # Security Source: https://docs.nmbr.co/components/security How the Nmbr Component secures communication between your app, your server, and the Nmbr API. The Nmbr Component is designed so that your API secret is never exposed to the browser. Every API call made by the component is authenticated using a JWT signature produced by your server, ensuring that only authorized requests reach the Nmbr API. ## How Request Signing Works When the Nmbr Component needs to interact with the Nmbr API (for example, to load payroll data or submit changes), it does not call the API directly. Instead, it follows a three-step signing flow: ### 1. The Component Intercepts the Request Before any API call leaves the browser, the Nmbr Component intercepts it and extracts the request body. This body contains the data that will be sent to the Nmbr API. ### 2. Your Server Signs the Request The component sends the request body to the **signing endpoint** you configured during [initialization](/components/getting-started#initialize-nmbr-components) (via `signingUrl` or a custom `sign` function). Your server: 1. Receives the JSON request body 2. Signs the body as a JWT using the **SHA-256 hash** of your API Secret and the **HS256** algorithm 3. Returns the signed JWT token to the component Because this step happens on your server, your API Secret is never sent to or accessible from the browser. ### 3. The Component Calls the Nmbr API The component takes the signed JWT returned by your server and includes it with the API request to the Nmbr API. The Nmbr API validates the signature to confirm the request was authorized by your server before processing it. Diagram showing the request signing flow between the browser, your server, and the Nmbr API ## Why This Architecture? ### API Secret Never Leaves Your Server The signing flow ensures that your API Secret is only ever used server-side. The browser never has access to it, which eliminates the risk of credential exposure through client-side code, browser extensions, or network inspection. ### You Control Authorization Your signing endpoint is a server-side route in your application. This means you can enforce your own authentication and authorization logic before signing any request. For example, you can verify that the current user is logged in and has permission to administer payroll before returning a signature. ### Every Request is Verified The Nmbr API validates the JWT signature on every incoming request. If a request has been tampered with or was not signed by your server, it will be rejected. ## Signing Endpoint Requirements Your signing endpoint must: * Accept `POST` requests with a JSON body * Sign the body as a JWT using the **HS256** algorithm * Use the **SHA-256 hash** of your API Secret as the signing key (hex-encoded or base64-encoded) * Return the signed JWT as plain text with a `201` status code * Be protected by your own authentication and authorization. See [Authenticating the Signing Request](#authenticating-the-signing-request) below For implementation examples in Ruby, Node.js, PHP, and .NET, see the [Getting Started guide](/components/getting-started#create-a-signing-endpoint). ## The Signed Payload The Component builds the JWT payload for each API request. Your `signingUrl` or `sign` function should sign the JSON it receives as-is. You do not need to create or change the JWT claims. If you inspect or build the payload yourself, set the `uri` claim to the API request path, including the query string when one is present. Exclude the scheme, host, and `/services/payroll` base path. For example: * `GET https://sandbox.nmbr.co/services/payroll/employees?per_page=5` β†’ `uri: "/employees?per_page=5"` * `GET https://sandbox.nmbr.co/services/payroll/employees` β†’ `uri: "/employees"` ## Authenticating the Signing Request Note: cookies are not sent to your signing endpoint by default. The following approaches are supported: ### Bearer Authentication Send a token in an HTTP header on every signing request and validate it server-side. The token can be an API key, signed token, or bearer JWT from your own auth system. Use the [custom `sign` function](#custom-signing-function) below to attach the header. `signingUrl` does not support custom headers. ### Cookie Authentication If your architecture specifically requires cookie-based auth, the [custom `sign` function](#custom-signing-function) below lets you write your own `fetch` call with `credentials: 'include'`. ## Custom Signing Function If your application architecture requires more control over the signing process (for example, if you need to add custom headers or use a different transport), you can provide a `sign` function instead of a `signingUrl` when initializing the component: ```typescript theme={null} window.components = nmbr.initialize({ companyId, partnerId, sign: async (json: string): Promise => { const response = await fetch('/your-custom-endpoint', { method: 'POST', headers: { Accept: 'text/plain', 'Content-Type': 'application/json', Authorization: `Bearer ${yourSessionToken}`, }, body: json, }); return response.text(); }, }); ``` This gives you full control over how the signing request is made while maintaining the same security guarantees. ## Best Practices * **Protect your signing endpoint** β€” Ensure it is behind authentication so that only logged-in users with the appropriate permissions can request signatures. * **Store your API Secret securely** β€” Use environment variables or a secrets manager. Never hard-code it in source files or commit it to version control. * **Use HTTPS** β€” All communication between the browser, your server, and the Nmbr API should be over HTTPS to prevent interception. * **Limit access** β€” Only users who need to administer payroll should be able to reach the signing endpoint. # Theming Source: https://docs.nmbr.co/components/theming Customize the look and feel of the Nmbr Component by changing the default colours and font. You can change the default colours and font used in the Nmbr Component by passing theme information via the `theme` property when instantiating the Nmbr Component: ```html payroll.html theme={null} ``` ## Font Family The `fontFamily` property allows you to customize the font used throughout the Nmbr Component. It only supports [Google Fonts](https://fonts.google.com/) β€” the component will automatically load the specified font from Google Fonts at runtime. | Property | Type | Default | Description | | ---------- | ------ | -------- | ----------------------------------------------------------------------------------------- | | fontFamily | string | `Roboto` | Any valid Google Font name. Falls back to "Roboto" if the provided font name isn't valid. | ## Type Information The `theme` property accepts an object with the following keys and value types: ```typescript theme={null} type ThemeColor = { main: string; light?: string; dark?: string; contrastText?: string; }; type CustomTheme = { fontFamily?: string; primary?: ThemeColor; secondary?: ThemeColor; warning?: ThemeColor; error?: ThemeColor; info?: ThemeColor; success?: ThemeColor; }; ``` The `string` provided as a `ThemeColor` property value must correspond to a CSS Hex Code (ex: `#ff0000`). If the `light`, `dark`, and `contrastText` values are not provided, they will be automatically inferred from the `main` color. If no `theme` values are defined, the Nmbr Component will use a set of default colors: ```typescript theme={null} theme: { primary: { main: '#3B82F6', }, secondary: { main: '#22C55E', }, error: { main: '#d32f2f', }, warning: { main: '#ed6c02', }, info: { main: '#0288d1', }, success: { main: '#2e7d32', }, }, ``` # Accounting Codes & Rules Source: https://docs.nmbr.co/guides/accounting/codes-and-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. 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**. 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 `subtype` (e.g. `salary`, `wage`) * `business_preset_id`, the highest-specificity match, mutually exclusive with `type`/`subtype` * 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. ### 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 ' \ --data '{ "business_entity_id": "", "type": "earning", "subtype": "salary", "expense_accounting_code_id": "", "liability_accounting_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` + `subtype` | "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` + `subtype` | 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` + `subtype` | 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`, `subtype`, 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/' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "accounting_settings": { "default_bank_accounting_code_id": "", "default_payroll_payable_accounting_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. # Accounting Integrations Source: https://docs.nmbr.co/guides/accounting/integrations Connect an accounting platform to import a Chart of Accounts and export journal entries. Nmbr integrates with **Xero** and **QuickBooks Online**. A connected integration imports a client's Chart of Accounts and tracking dimensions, and exports each payroll's journal entries into their books, tag allocations included. An integration comes together in three phases, each with its own cadence: 1. **Register an OAuth application** with each platform you support: one application per platform, one time. 2. **Connect the client's account**: each Business Entity connects its own Xero or QuickBooks account. 3. **Import and export**: sync the Chart of Accounts and tracking dimensions as the client's books change, and export journal entries payroll by payroll. ## Registering your OAuth application Register a developer account with the platform and create an OAuth 2.0 application, with the redirect URI set to: ``` https://uni-api.nmbr.co/oauth/code ``` Then add the application's client ID and secret in the Nmbr Portal. Platform notes: * **Xero**: create a [Demo company](https://central.xero.com/s/article/Use-the-demo-company) to test against. * **QuickBooks**: select the "Sandbox" environment when creating a testing application, and 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) to test against. ## Connecting a client's account Request an authentication URL and send the client there to approve access: **Request** ```bash theme={null} curl --request POST \ --url 'https://sandbox.nmbr.co/services/payroll/integrations/xero/authenticate' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "business_entity_id": "" }' ``` **Response** ```json theme={null} { "id": "xero", "object": "oauth_auth_url", "data": { "authentication_url": "https://login.xero.com/identity/connect/authorize?..." } } ``` Once the client approves, Nmbr stores the connection and sends an `integration_authentication_success` (or `integration_authentication_failure`) [webhook](/api/overview/webhook-structure) on the Business Entity. Clients can also be connected directly in the Nmbr Portal. If you run the OAuth flow against your own application yourself, you can supply the resulting tokens with [`POST /integrations/{integration}/connection`](/api-reference/integrations/import-a-partner-supplied-oauth-connection) instead. [`GET /integrations`](/api-reference/integrations/list-integrations) lists both platforms for a Business Entity, with `is_enabled` and the connected account's details. Disconnect with [`DELETE /integrations/{integration}`](/api-reference/integrations/delete-an-integration). ## Importing the Chart of Accounts After a client connects, import their Chart of Accounts into their Business Entity: ```bash theme={null} curl --request POST \ --url 'https://sandbox.nmbr.co/services/payroll/integrations/xero/sync' \ --header 'Authorization: Bearer ' \ --data '{ "business_entity_id": "", "sync": "accounting_codes" }' ``` The sync runs in the background: the endpoint returns `202 Accepted`, and an `integration_sync_account_codes_complete` (or `_failure`) webhook fires when it finishes. Imported accounts are limited to the `expense`, `liability`, and `bank` types. Each imported code carries the platform's identifier for its account, which the export uses to address rows. If an import leaves duplicates of codes you created by hand, [merge them](/guides/accounting/codes-and-rules#merging-accounting-codes) into the imported ones. ## Importing tracking dimensions Accounting platforms also expose tracking dimensions: Xero tracking categories; QuickBooks classes, departments, and projects. Each imported dimension becomes a Tag Group and its values become Tags, ready for [tag allocation](/guides/accounting/tagging). List the dimensions a connection exposes with [`GET /integrations/{integration}/tracking_dimensions`](/api-reference/integrations/list-integration-tracking-dimensions), then import with the `category`, `department`, or `project` sync type: ```bash theme={null} curl --request POST \ --url 'https://sandbox.nmbr.co/services/payroll/integrations/quickbooks/sync' \ --header 'Authorization: Bearer ' \ --data '{ "business_entity_id": "", "sync": "department" }' ``` An `integration_sync_tags_complete` (or `_failure`) webhook fires when the import finishes. Imported tag groups and tags keep their external identifiers, so re-running the sync updates them in place. See [Setting up tag groups and tags](/guides/accounting/tagging#setting-up-tag-groups-and-tags). ## Exporting journal entries Export a payroll's journal entries into the connected platform: ```bash theme={null} curl --request POST \ --url 'https://sandbox.nmbr.co/services/payroll/integrations/xero/sync' \ --header 'Authorization: Bearer ' \ --data '{ "payroll_id": "", "sync": "journal_entries" }' ``` The export runs in the background and fires an `integration_sync_journal_entries_complete` (or `_failure`) webhook on the payroll. Only the two payroll-level entries are exported, the [accrual entry and the payment entry](/guides/accounting/journal-entries). Zero-amount rows are skipped, and row descriptions are prefixed with your partner name and the pay schedule so they read clearly in the client's books. For the export to succeed: * Every exportable row needs an accounting code with the connected platform's identifier: one imported from the platform, or [merged](/guides/accounting/codes-and-rules#merging-accounting-codes) into one that was. * The Business Entity must have its [default **bank** and **payroll payable** codes](/guides/accounting/codes-and-rules#business-entity-accounting-settings) set. To stop payrolls from being approved before their entries can export, enable `block_approval_on_missing_export_identifiers` in the Business Entity's [accounting settings](/guides/accounting/codes-and-rules#business-entity-accounting-settings). Rows carry their tags into the platform: allocations land as Xero tracking categories, or QuickBooks classes, departments, and projects. After a successful export, the entry's `integrations.xero.reference` or `integrations.quickbooks.reference` holds the platform's id for the created journal. # Journal Entries Source: https://docs.nmbr.co/guides/accounting/journal-entries How Nmbr generates payroll journal entries and what the Journal Entry report contains. 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/accounting/tagging#journal-entry-tracking-dimensions) and [Retrieving dimension tags](/guides/accounting/tagging#retrieving-dimension-tags) for the full model. ## Sample Journal Entry JSON ```json theme={null} { "id": "", "object": "journal_entry", "data": { "type": "payroll_recording", "title": "Payroll Accrual Entry", "payroll": { "id": "", "object": "payroll", "links": { "self": "/payrolls/" } }, "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": "", "object": "journal_entry_row", "data": { "type": "debit", "amount": 5000, "code": "6000", "description": "Semi-Monthly Schedule #1 - Wages Expense", "account_code": { "id": "", "object": "accounting_code", "links": { "self": "/accounting_codes/" } }, "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": "", "object": "journal_entry_row", "data": { "type": "debit", "amount": 403.62, "code": "6010", "description": "Semi-Monthly Schedule #1 - Employer Contributions Expense", "account_code": { "id": "", "object": "accounting_code", "links": { "self": "/accounting_codes/" } }, "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": "", "object": "journal_entry_row", "data": { "type": "credit", "amount": 1930.24, "code": "2200", "description": "Semi-Monthly Schedule #1 - Statutory Withholdings Payable", "account_code": { "id": "", "object": "accounting_code", "links": { "self": "/accounting_codes/" } }, "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": "", "object": "journal_entry_row", "data": { "type": "credit", "amount": 3473.38, "code": "2210", "description": "Semi-Monthly Schedule #1 - Net Pay Payable", "account_code": { "id": "", "object": "accounting_code", "links": { "self": "/accounting_codes/" } }, "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/" } } ``` > 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`. # Overview Source: https://docs.nmbr.co/guides/accounting/overview How Nmbr's accounting features fit together: accounting codes, journal entries, and export. Businesses that run payroll have to record it in their accounting: what they paid in wages, what they withheld for tax, and what they still owe. This usually lives in accounting software such as Xero or QuickBooks. Nmbr gives you the tools to produce those records for each payroll and export them there. ## How a payroll is recorded You don't need an accounting background for these guides. This section is a short introduction to the accounting concepts Nmbr's features build on. A payroll moves money twice. When it runs, the business takes on **expenses** (gross wages, employer contributions) and **liabilities** (net pay owed to employees, taxes owed to the CRA). When those amounts are later paid out, cash leaves the bank. Accounting records each movement as a **journal entry**: a few lines, each assigning an amount to an account, like wages or taxes payable. A payroll produces two journal entries: * The **accrual entry** records the payroll when it runs: the expenses it created, and the liabilities now owed. * The **payment entry** records the cash leaving the bank to settle those liabilities. Every line in those entries is recorded against an account in the business's **Chart of Accounts**: the named accounts it tracks money in, such as "Wages Expense", "Payroll Payable", and its bank account. Everything in these guides exists to produce those two entries: **accounting codes** represent those accounts in Nmbr (typed expense, liability, or bank), **rules** put the right codes on every payroll line, **tags** control how the entries break down, **segment templates** compose multi-part account references for systems that need them, and **integrations** deliver the entries into the client's accounting software. ## Concepts * **Accounting code**: an account from the business's Chart of Accounts, typed as expense, liability, or bank. See [Accounting Codes & Rules](/guides/accounting/codes-and-rules). * **Accounting code rule**: matches line items and assigns their expense and liability codes automatically. See [Accounting Codes & Rules](/guides/accounting/codes-and-rules). * **Journal entry**: the accrual and payment entries Nmbr generates for each payroll. See [Journal Entries](/guides/accounting/journal-entries). * **Tag and tag group**: dimensions for splitting a line item's cost across departments, projects, or locations. See [Tagging](/guides/accounting/tagging). * **Segment template**: composes a custom, multi-part code, such as `5000-ENG-TOR`, on the Journal Entry report. See [Journal Entry Segment Templates](/guides/accounting/segment-templates). * **Integration**: a connection to Xero or QuickBooks Online that imports a Chart of Accounts and exports journal entries. See [Accounting Integrations](/guides/accounting/integrations). ## What you can set up Combine these pieces to match how a client keeps their books. The conventional flow runs on accounting codes, matched to the client's Chart of Accounts: they drive the journal entries and the export. When a fixed code list doesn't fit, segmented codes offer more flexibility on the journal report. **A complete journal entry for every payroll.** Accounting codes represent the business's accounts, rules resolve an expense and a liability code for every line item, and the default bank and payroll payable codes supply the bank and payable rows. Each payroll then generates its accrual and payment entries automatically. See [Accounting Codes & Rules](/guides/accounting/codes-and-rules) and [Journal Entries](/guides/accounting/journal-entries). **Costs broken down by department, project, or location.** Tags split line items across the dimensions a client tracks. Journal entry rows follow the splits and carry the tags as tracking dimensions, and rules can route tagged line items to their own accounts. See [Tagging](/guides/accounting/tagging). **Entries delivered into the client's accounting software.** The built-in integration connects Xero or QuickBooks Online, imports the client's Chart of Accounts and tracking dimensions, and exports each payroll's entries back. For any other system, you can read journal entries through the [API](/api-reference/journal-entries/list-journal-entries) and deliver them yourself. See [Accounting Integrations](/guides/accounting/integrations). **Account references in the format another system expects.** Segment templates compose a segmented reference, like `5000-ENG-TOR` (a base code plus department and location), on the Journal Entry report. They are carried by the same accounting code rules that route codes, but resolve on their own when the report is built. See [Journal Entry Segment Templates](/guides/accounting/segment-templates). # Journal Entry Segment Templates Source: https://docs.nmbr.co/guides/accounting/segment-templates Build a custom, multi-part code for the Journal Entry report. Some companies use **segmented account codes** in their journal entries: a single account reference assembled from parts, such as a base code, a department, and a location, combined into a value like `5000-ENG-TOR` rather than one flat code. A **journal entry** is how accounting records a transaction: each line assigns an amount to an account, like wages or taxes payable. A payroll produces one, and the **Journal Entry report** is that entry laid out line by line. Nmbr offers **segment templates** to build that code on the Journal Entry report. You define how the parts are assembled, and Nmbr renders the result into two columns, **Generated Expense Code** and **Generated Liability Code**. A payroll line records both an **expense** (the employer's cost) and the **liability** it creates (what's owed until it's paid out). That's why segments, templates, and the report columns all come in an expense and a liability form. Segment templates are optional, and each applies only to the line items it matches. They build on Nmbr's accounting concepts, so if those are new to you, start with the [Accounting overview](/guides/accounting/overview). ## How this differs from an accounting code A generated code is not an accounting code. Both can appear on the Journal Entry report, but they come from separate systems. **[Accounting codes](/guides/accounting/codes-and-rules)** * A distinct entity in Nmbr: a fixed expense or liability code. * Often imported from an external accounting platform, and drive the automated export back to it (Xero, QuickBooks). * Assigned to a line manually, or by accounting code rules based on attributes like the primary tag or line item type. * Rules are driven by a single primary tag group. **Generated codes** * Computed when the Journal Entry report is built, from a segment template you define globally. * Can combine any number of tag groups, accounting codes, and freeform text. * Not a fixed, labelled value from a known set. * Never part of the export to Xero or QuickBooks. ## How a generated code is built A generated code is built from a **segment template** on an accounting code rule: an ordered list of **segments**, some of which read values from tags. ### The segment template A segment template is defined on a **global** accounting code rule (one with no tag or tag group scope). A rule holds one template per side, in `expense_segment_template` and `liability_segment_template`. When the Journal Entry report is built, Nmbr renders the template's segments in order and joins them into that side's generated code. ### Segments Each segment resolves to a value from one of three sources: * **`accounting_code`**: a fixed accounting code's `code`. Set `id` to the accounting code's `id`. * **`tag_group`**: a code carried by one of the row's tags. Set `tag_group_id` to the tag group's `id`. * **`text`**: a literal string you supply. A `tag_group` segment reads its value from the tag itself. Each tag carries a per-side code, `expense_segment` and `liability_segment`, set when you create or update the tag (see [Setting up tag groups and tags](/guides/accounting/tagging#setting-up-tag-groups-and-tags)). On each report row, the segment takes the code from the row's tag in that group. ### Formatting The `accounting_code` and `tag_group` segments also accept optional formatting: * `prefix` / `suffix`: literal strings wrapped around the resolved value. * `transform`: an ordered list of `uppercase`, `lowercase`, `alphanumeric` (strip non-alphanumeric characters). * `max_length`: truncate the resolved value to this many characters. * `fallback`: a value to use when the segment resolves empty. Without one, an empty segment is dropped, prefix and suffix included. Each of those segments is processed in a fixed order: resolve the raw value, apply the fallback if it's empty, run the transforms, truncate to `max_length`, then wrap with `prefix` and `suffix`. ### The result When a rule's template matches a line, the rendered string appears in **Generated Expense Code** or **Generated Liability Code** on the Journal Entry report. The columns are always present; on a given line only the relevant side is filled. Bank, payable, and total rows stay blank. ### Which template applies Templates resolve on their own when the report is built, separately from how [accounting codes are routed](/guides/accounting/codes-and-rules#rule-precedence) during payroll calculation. The precedence is the same: for each side of a line, Nmbr uses the template from the most specific matching global rule. 1. `business_preset_id` 2. `type` + `subtype` 3. `type` 4. the catch-all: no `type`, `subtype`, or `business_preset_id` The expense and liability sides resolve independently, so a line's two columns can come from different rules. Set one catch-all template as a default, then override it for specific line item types. Because templates are defined only on global rules, this precedence has no tag dimension. A tag or tag-group-scoped rule never carries a template. ## Example Give two tags an expense segment. The "Engineering" department tag: ```json theme={null} { "expense_segment": "eng" } ``` And the "Toronto" location tag: ```json theme={null} { "expense_segment": "tor" } ``` Set an expense template on the global rule for wages. It emits the wages accounting code, then the department, then the location, each uppercased. The department falls back to `GEN` when a row has none: ```json theme={null} { "segments": [ { "type": "accounting_code", "id": "agcode_01HXWAGES00000000000000" }, { "type": "tag_group", "tag_group_id": "taggrp_01HXDEPT00000000000000", "prefix": "-", "transform": ["uppercase"], "fallback": "GEN" }, { "type": "tag_group", "tag_group_id": "taggrp_01HXCITY00000000000000", "prefix": "-", "transform": ["uppercase"] } ] } ``` For an Engineering wages line in Toronto where the wages code is `5000`, the report's **Generated Expense Code** reads: ``` 5000-ENG-TOR ``` A wages line with no department resolves the second segment to its fallback: `5000-GEN-TOR`. ## Behaviour and limits * **Global rules only.** Templates are defined on rules with no tag or tag group scope. * **Report only.** Generated codes never affect the accounting code that syncs to the connected accounting platform. See [Exporting journal entries](/guides/accounting/integrations#exporting-journal-entries). ## Related * [Tagging and Journal Entry Tracking](/guides/accounting/tagging) for tags, tag groups, and how they split allocations. * [Accounting Codes & Rules](/guides/accounting/codes-and-rules) for accounting codes, rules, and precedence. * [Journal Entries](/guides/accounting/journal-entries) for the Journal Entry report. # Tagging & Journal Entry Tracking Source: https://docs.nmbr.co/guides/accounting/tagging Allocate payroll line items across tags for accounting codes and journal entries ## Overview Tags categorize and allocate payroll amounts across dimensions like department, project, or location, so costs can be tracked, split, and mapped to the right accounting codes automatically. Each line item can carry a tag assignment, a structure that defines how that line item's dollar amount is distributed across one or more tags. Those allocations are used to determine accounting codes and detailed journal entries. The typical flow looks like this: 1. **Define tag groups and tags**: create tag groups ("Department", "Project") and tags within them ("Engineering", "Sales", "Project Alpha") 2. **Assign tags**: set tag assignments on work assignments, generators, or individual line items to describe how costs are distributed 3. **Configure accounting code rules**: define rules that map tags to expense and liability accounting codes, resolved automatically during payroll calculation 4. **Generate journal entries**: tag allocations produce journal entry rows, one per allocation per tracking dimension, ready to export to the connected accounting system ## Concepts * **[Tag groups and tags](#setting-up-tag-groups-and-tags)**: tag groups (e.g. "Department") and their values (e.g. "Engineering", "Sales") * **[Tag assignments and allocations](#tag-assignments-and-allocations)**: how an amount is distributed across tags, with one or more allocations * **[Assigning tags](#assigning-tags)**: tag assignments can be set on work assignments, generators, and line items, and [resolve down](#tag-resolution-and-precedence) to line items automatically * **[Primary tag group](#primary-tag-group)**: the tag group whose accounting code rules are applied * **[Accounting code rules](#accounting-code-rules)**: map tags to expense and liability accounting codes * **[Derived tags on statutory withholdings](#derived-tags-on-statutory-withholdings)**: withholdings calculate their allocations from applicable remuneration * **[Journal entry tracking dimensions](#journal-entry-tracking-dimensions)**: tag groups marked as tracking dimensions split journal entry rows with matched accounting codes ## Setting up tag groups and tags Tag groups represent a category to track (e.g. "Department"). Tags are the values within that group (e.g. "Engineering", "Sales"). Each tag group belongs to a business entity. A tag group can also be marked as a journal entry tracking dimension; see [Journal entry tracking dimensions](#journal-entry-tracking-dimensions). 1. [Create a tag group](/api-reference/tag-groups/create-a-tag-group) for each category to track 2. [Create tags](/api-reference/tags/create-a-tag) within each group Tag groups carry a few optional properties beyond their label: * `color`: a hex colour (e.g. `#AABBCC`) used for display. * `is_component_locked`: when `true`, the tags in this group cannot be edited through the embedded Component. They can still be managed through the API. * `is_journal_entry_dimension`: see [Journal entry tracking dimensions](#journal-entry-tracking-dimensions). * `archived_at`: archived tag groups (and tags) are excluded from index listings by default. Pass `include_archived=true` to include them. * `is_deletable`: `false` while the group is the primary tag group, or while any of its tags are used in active allocations. The same applies to individual tags. Tag groups and tags imported from an accounting integration carry the external identifiers (`integrations.xero`, `integrations.quickbooks`) that link them back to the source system, so they round-trip on re-sync. See [Importing tracking dimensions](/guides/accounting/integrations#importing-tracking-dimensions). See the [Tag Groups](/api-reference/tag-groups/list-tag-groups) and [Tags](/api-reference/tags/list-tags) API reference for full details. Tags can also carry per-side codes used to compose a formatted code on the Journal Entry report. See [Journal Entry Segment Templates](/guides/accounting/segment-templates). ## Tag assignments and allocations A **tag assignment** describes how a line item's amount is distributed across tags. Tag assignments can be set on work assignments, generators, and line items. Each contains a `unit` that determines how allocations are measured, and one or more **tag allocations**, each with a set of tags and an allocation value. #### Example tag assignment structure ```jsonc theme={null} { "tag_assignment": { "unit": "percentage", "tag_allocations": [ { "tags": [ "", // From department tag group "", // From project tag group ], "value": 60, }, { "tags": [ "", // From department tag group ], "value": 40, }, ], }, } ``` In this example, 60% of the amount is attributed to the Engineering department on Project Alpha, and 40% to the Sales department. Each allocation can combine tags from different tag groups, but only one tag per group is allowed in each allocation. Allocations must sum to less than or equal to 100%. Any unallocated remainder falls back to the line item's own accounting codes. If no accounting code can be determined, the payroll is blocked until the allocation is resolved. ### Supported units by resource The `unit` on a tag assignment controls how allocation values are interpreted. Available units depend on the resource type. Work assignments and generators only support `percentage` because they define default allocations before line item amounts are known. Only line items have concrete dollar values and hours that can be allocated directly. | Resource | Supported units | | --------------------------------------------------------------------------------------------------------- | ------------------------------- | | Work assignment | `percentage` | | Pay rate, overtime rate, employee benefit, employer benefit, reimbursement, earning, allowance, deduction | `percentage` | | Earning line item | `percentage`, `amount`, `hours` | | Deduction, allowance, reimbursement, employee benefit, employer benefit line item | `percentage`, `amount` | ## Assigning tags ### Work assignments A `tag_assignment` on a work assignment defines the default allocation for all of that employee's line items. Work assignment tag assignments use the `percentage` unit. Each allocation defines what percentage of the total amount is attributed to those tags. Allocations must sum to less than or equal to 100%. Pass `tag_assignment` when [creating](/api-reference/work-assignments/create-a-work-assignment) or [updating](/api-reference/work-assignments/update-a-work-assignment) a work assignment. Pass `null` to remove it. Use `?expand=tag_assignment` to include it in responses. ### Generators In this guide, **generators** refers to the resources that produce line items: pay rates, overtime rates, earnings, deductions, allowances, reimbursements, and benefits. Generators support a `tag_assignment` that overrides the work assignment's `tag_assignment` for line items created by that generator. Generator tag assignments use `percentage` allocations only. Pass `tag_assignment` when creating or updating any generator resource. ### Line items Line items support a `custom_tag_assignment` that overrides the managed tag assignment inherited from the work assignment or generator. #### Allocation units | Unit | Description | Validation | Use case | | ------------ | ----------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------- | | `percentage` | Split by percentage of total amount | Allocations must sum to less than or equal to 100% | Default, same as work assignments and generators | | `hours` | Split by hours worked | Allocations must sum to less than or equal to the line item's `hours` | Earning line items only, attribute costs by hours per tag | | `amount` | Split by fixed dollar amounts | Allocations must sum to less than or equal to the line item's `amount` | Attribute exact dollar amounts per tag | Earning line items accept all three units. Non-earning line items (deductions, allowances, reimbursements, benefits) accept `percentage` and `amount` only. #### Expanding tag assignments Line items expose several expandable tag properties. Each returns the full tag assignment structure: | Expand | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------- | | `tag_assignment` | The effective tag assignment: the `custom_tag_assignment` if set, otherwise the `managed_tag_assignment` | | `custom_tag_assignment` | Optional override: if set, these allocations are used instead of the managed value | | `managed_tag_assignment` | The auto-inherited allocation from the work assignment or generator | | `tag_assignment_amounts` | The resolved dollar distribution for the line item | ### Patching a tag assignment To adjust an existing tag assignment without resending the whole structure, pass `tag_assignment_patch` instead of `tag_assignment` on a work assignment or generator. The two keys are mutually exclusive. | Field | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `add_tags` | Tag IDs to add to every existing allocation. Adding a tag replaces any other tag from the same tag group on that allocation. | | `remove_tags` | Tag IDs to remove from every existing allocation. An allocation left with no tags is deleted; the distribution strategy decides its value. | | `distribution_strategy` | Governs the value of allocations deleted by `remove_tags`. Defaults to `reallocate`. | The `distribution_strategy` accepts: * `reallocate`: spread the deleted value proportionally across the remaining allocations. * `unallocated`: drop the value; the assignment's allocations will sum to less than before. * `error`: refuse the patch if any allocation would be deleted. ## Tag resolution and precedence Line items on draft payrolls automatically receive a `managed_tag_assignment`, resolved from the generator's `tag_assignment` if set, otherwise from the work assignment's `tag_assignment`. If a `custom_tag_assignment` is set on the line item, it takes precedence over the managed value. The effective `tag_assignment` (used for accounting code matching and journal entries) is the `custom_tag_assignment` if one exists, otherwise the `managed_tag_assignment`. Tag resolution only applies to draft payrolls. Once a payroll is approved, its tag assignments are locked. Subsequent changes to work assignment or generator tag assignments will not affect it. When a work assignment's `tag_assignment` is updated, draft line items whose generator has no `tag_assignment`, have their `managed_tag_assignment` updated to match. When a generator's `tag_assignment` is updated, all of its draft line items have their `managed_tag_assignment` updated to match. ## Primary tag group A business entity can designate one tag group as its **primary tag group**. * Tags from this group can be linked to [accounting code rules](#accounting-code-rules), enabling automatic accounting code matching * When set, every tag allocation must include a tag from the primary tag group Set the primary tag group through the business entity's [`accounting_settings.primary_tag_group`](/api-reference/business-entities/update-a-business-entity). The top-level `primary_tag_group_id` is a deprecated alias. Setting a primary tag group also flags it as a journal entry dimension. If the primary tag group is changed, draft payrolls with allocations missing a tag from the new primary group will be blocked until corrected. ## Accounting code rules Tags and tag groups can scope accounting code rules, so a line item's tags influence which expense and liability codes it receives. A tag- or tag-group-scoped rule takes precedence over a global rule, and matches tags in the [primary tag group](#primary-tag-group). See [Accounting Codes & Rules](/guides/accounting/codes-and-rules#rule-precedence) for the full precedence model (tag, tag group, and global tiers) and how rules resolve during payroll calculation. ## Derived tags on statutory withholdings Statutory withholding line items (CPP, EI, income tax, etc.) are system-calculated and cannot be directly tagged. Instead, they derive their tag assignments from the applicable remuneration on the pay stub. This behaviour is controlled by the business entity's `accounting_settings.resolve_journal_entry_stat_withholdings` setting. When `true`, each withholding is split across the same tags as its source earnings. When `false`, each withholding stays a single unsplit row in journal entries. When enabled, after payroll calculation the system examines which remuneration line items contribute to each withholding and builds a weighted percentage distribution based on their resolved dollar amounts, regardless of whether the original tag assignment used `percentage`, `hours`, or `amount` units. This ensures withholding amounts follow the same distribution as the remuneration that generated them. ### Example: statutory withholdings derived from pensionable earnings **Earnings on the pay stub:** | Line item | Amount | Engineering | Sales | | -------------- | ------- | ----------- | ----- | | Salary earning | \$3,000 | 100% | | | Bonus earning | \$2,000 | | 100% | **Derived statutory withholdings:** | Line item | Amount | Engineering | Sales | | --------------- | ------ | ----------- | ----------- | | CPP withholding | \$300 | 60% (\$180) | 40% (\$120) | | EI withholding | \$150 | 60% (\$90) | 40% (\$60) | The withholdings inherit a 60/40 distribution derived from the weighted remuneration (\$3,000 Engineering / \$2,000 Sales). ## Journal entry tracking dimensions Tag groups can be marked as **tracking dimensions** on journal entries. When enabled, each line item allocation produces a separate journal entry row, with matched accounting codes and the tag from each tracking dimension. The [primary tag group](#primary-tag-group) is always a tracking dimension. Up to two additional tag groups can be marked as tracking dimensions by setting `is_journal_entry_dimension` to `true`. Tagged payroll data produces structured journal entries with tracking detail per tag group. ### Example: journal entry rows with tracking dimensions Given a salary earning of \$5,000 tagged 60% Engineering / 40% Sales: **Without tracking dimensions:** | Account | Debit | Credit | | ----------------- | ------- | ------- | | Salary Expense | \$5,000 | | | Payroll Liability | | \$5,000 | **With Department and Project as tracking dimensions:** | Account | Debit | Credit | Department | Project | | ----------------- | ------- | ------- | ----------- | ------------- | | Salary Expense | \$3,000 | | Engineering | Project Alpha | | Salary Expense | \$2,000 | | Sales | | | Payroll Liability | | \$3,000 | Engineering | Project Alpha | | Payroll Liability | | \$2,000 | Sales | | Each allocation produces its own debit and credit row, with the matched accounting codes and tracking dimension tags. ### Retrieving dimension tags Each journal entry row carries up to three dimension tags, one per tracking dimension: `dimension_1_tag`, `dimension_2_tag`, and `dimension_3_tag`. A tag group keeps the same slot across every row in a payroll. Slots are not pinned to a fixed group, so read each tag's `tag_group` to tell which dimension it represents rather than relying on position. The tags sit two levels down: rows are nested under the journal entry, and each tag is nested under a row. Both are returned as stubs by default, so resolving the tags inline takes a nested expand. Expand `journal_entry_rows.dimension_1_tag`, `journal_entry_rows.dimension_2_tag`, and `journal_entry_rows.dimension_3_tag` for the dimensions to resolve. Each expanded row then includes the full tag for every dimension it carries: ```json theme={null} { "id": "accjr_01...", "object": "journal_entry_row", "data": { "type": "debit", "amount": 2500, "code": "5110", "dimension_1_tag": { "id": "tag_01AURORA...", "object": "tag", "data": { "label": "Aurora", "tag_group": { "id": "tgrp_01...", "object": "tag_group" } } }, "dimension_2_tag": { "id": "tag_01MTL...", "object": "tag", "data": { "label": "Montreal", "tag_group": { "id": "tgrp_01...", "object": "tag_group" } } }, "dimension_3_tag": null } } ``` A dimension with no tag on a row returns `null`. Without the expand, each dimension tag is returned as a stub with `id` and `links` only. ## End-to-end example This example walks through the full tagging flow, from setup to journal entries. * Quebec-based business entity with two employees: Marie (Montreal) and Luc (Quebec City) * Both earn \$60,000 salary, paid semi-monthly (\$2,500 per period) * Both work on Project Aurora * Luc also receives an \$833.33 bonus for work on Project Beacon ### 1. Set up tags 1. Create a "Project" tag group with two tags: **Aurora** and **Beacon** 2. Create a "Location" tag group with two tags: **Montreal** and **Quebec City** 3. Set "Project" as the business entity's primary tag group (`accounting_settings.primary_tag_group`) 4. Mark both tag groups as journal entry tracking dimensions (`is_journal_entry_dimension: true`)
API structure ```jsonc theme={null} // Project tag group { "id": "tgrp_01J...", "object": "tag_group", "data": { "label": "Project", "label_translations": { "en": "Project", "fr": "Projet" }, "description": null, "is_component_locked": false, "is_journal_entry_dimension": true, "business_entity": { "id": "be_01...", "object": "business_entity" } } } // Aurora project tag { "id": "tag_01AURORA...", "object": "tag", "data": { "label": "Aurora", "label_translations": { "en": "Aurora", "fr": "Aurora" }, "description": null, "tag_group": { "id": "tgrp_01J...", "object": "tag_group" }, "business_entity": { "id": "be_01...", "object": "business_entity" } } } // Beacon project tag { "id": "tag_01BEACON...", "object": "tag", "data": { "label": "Beacon", "label_translations": { "en": "Beacon", "fr": "Beacon" }, "description": null, "tag_group": { "id": "tgrp_01J...", "object": "tag_group" }, "business_entity": { "id": "be_01...", "object": "business_entity" } } } // The "Location" tag group (tgrp_01L...) with tags "Montreal" and "Quebec City" // follows the same structure as above. ```
### 2. Create accounting code rules Define rules for the primary tag group to map each project to accounting codes: | Tag | Type | Expense code | Liability code | | ------ | --------------------- | ------------------------------- | ------------------------------- | | Aurora | Earning | 5110 (Aurora Salaries) | 2100 (Aurora Payroll Liability) | | Aurora | Statutory withholding | 5120 (Aurora Stat Withholdings) | 2110 (Aurora Stat Payable) | | Beacon | Earning | 5210 (Beacon Salaries) | 2200 (Beacon Payroll Liability) | | Beacon | Statutory withholding | 5220 (Beacon Stat Withholdings) | 2210 (Beacon Stat Payable) | Each project has an earning rule and a stat withholding rule. No tag-only fallbacks are needed since all line items in this example are covered by type-level rules.
API structure ```jsonc theme={null} // Aurora: earning rule { "id": "acr_01A...", "object": "accounting_code_rule", "data": { "business_entity": { "id": "be_01...", "object": "business_entity" }, "tag": { "id": "tag_01AURORA...", "object": "tag" }, // Aurora project tag "type": "earning", "subtype": null, "business_preset": null, "expense_accounting_code": { "id": "ac_5110...", "object": "accounting_code" }, // Aurora Salaries "liability_accounting_code": { "id": "ac_2100...", "object": "accounting_code" } // Aurora Payroll Liability } } // Aurora: stat withholding rule { "id": "acr_01B...", "object": "accounting_code_rule", "data": { "business_entity": { "id": "be_01...", "object": "business_entity" }, "tag": { "id": "tag_01AURORA...", "object": "tag" }, // Aurora project tag "type": "statutory_withholding", "subtype": null, "business_preset": null, "expense_accounting_code": { "id": "ac_5120...", "object": "accounting_code" }, // Aurora Stat Withholdings "liability_accounting_code": { "id": "ac_2110...", "object": "accounting_code" } // Aurora Stat Payable } } // Beacon: earning rule { "id": "acr_01C...", "object": "accounting_code_rule", "data": { "business_entity": { "id": "be_01...", "object": "business_entity" }, "tag": { "id": "tag_01BEACON...", "object": "tag" }, // Beacon project tag "type": "earning", "subtype": null, "business_preset": null, "expense_accounting_code": { "id": "ac_5210...", "object": "accounting_code" }, // Beacon Salaries "liability_accounting_code": { "id": "ac_2200...", "object": "accounting_code" } // Beacon Payroll Liability } } // Beacon: stat withholding rule { "id": "acr_01D...", "object": "accounting_code_rule", "data": { "business_entity": { "id": "be_01...", "object": "business_entity" }, "tag": { "id": "tag_01BEACON...", "object": "tag" }, // Beacon project tag "type": "statutory_withholding", "subtype": null, "business_preset": null, "expense_accounting_code": { "id": "ac_5220...", "object": "accounting_code" }, // Beacon Stat Withholdings "liability_accounting_code": { "id": "ac_2210...", "object": "accounting_code" } // Beacon Stat Payable } } ```
### 3. Assign tags to work assignments Both employees' work assignments are tagged 100% Aurora, with their respective location: **Marie:** * 100% to `Project: Aurora`, `Location: Montreal` **Luc:** * 100% to `Project: Aurora`, `Location: Quebec City`
API structure: work assignment with tag\_assignment ```jsonc theme={null} // Marie's work assignment with ?expand=tag_assignment { "id": "wa_01M...", "object": "work_assignment", "data": { // ... "tag_assignment": { "unit": "percentage", "tag_allocations": [ { "tags": [ { "id": "tag_01AURORA...", "object": "tag", "data": { "label": "Aurora", "tag_group": { "id": "tgrp_01J...", "object": "tag_group" }, "business_entity": { "id": "be_01...", "object": "business_entity", }, }, }, { "id": "tag_01MTL...", "object": "tag", "data": { "label": "Montreal", "tag_group": { "id": "tgrp_01L...", "object": "tag_group" }, "business_entity": { "id": "be_01...", "object": "business_entity", }, }, }, ], "value": 100, "expense_accounting_code": null, "liability_accounting_code": null, }, ], }, }, } ```
### 4. Line items on the pay stub In this example, the salary line items resolve their `managed_tag_assignment` from the work assignment. Since Luc's bonus is for work on Project Beacon, a `custom_tag_assignment` on that line item overrides the managed Aurora tag with Beacon. When expanded, the effective `tag_assignment` returns the `custom_tag_assignment` if one is set, otherwise the `managed_tag_assignment`. **Marie's salary earning (\$2,500.00):** * Managed tag assignment: 100% to `Project: Aurora`, `Location: Montreal` * Custom tag assignment: none * **Effective tag assignment:** 100% to `Project: Aurora`, `Location: Montreal` **Luc's salary earning (\$2,500.00):** * Managed tag assignment: 100% to `Project: Aurora`, `Location: Quebec City` * Custom tag assignment: none * **Effective tag assignment:** 100% to `Project: Aurora`, `Location: Quebec City` **Luc's bonus earning (\$833.33):** * Managed tag assignment: 100% to `Project: Aurora`, `Location: Quebec City` * Custom tag assignment: 100% to `Project: Beacon`, `Location: Quebec City` * **Effective tag assignment:** 100% to `Project: Beacon`, `Location: Quebec City` ### 5. Matched accounting codes Each line item's tag allocations are matched against accounting code rules: | Employee | Line item | Primary tag | Matched rule | Expense code | Liability code | | -------- | --------------- | ----------- | --------------------- | ------------------------------- | ------------------------------- | | Marie | Salary earning | Aurora | Earning | 5110 (Aurora Salaries) | 2100 (Aurora Payroll Liability) | | Luc | Salary earning | Aurora | Earning | 5110 (Aurora Salaries) | 2100 (Aurora Payroll Liability) | | Luc | Bonus earning | Beacon | Earning | 5210 (Beacon Salaries) | 2200 (Beacon Payroll Liability) | | Marie | QPP withholding | Aurora | Statutory withholding | 5120 (Aurora Stat Withholdings) | 2110 (Aurora Stat Payable) | | Luc | QPP withholding | Aurora | Statutory withholding | 5120 (Aurora Stat Withholdings) | 2110 (Aurora Stat Payable) | | Luc | QPP withholding | Beacon | Statutory withholding | 5220 (Beacon Stat Withholdings) | 2210 (Beacon Stat Payable) | Luc's QPP withholding has two allocations (75% Aurora / 25% Beacon), each resolved independently against its matching rule.
API structure: Luc's bonus earning with resolved tag allocations and accounting codes ```jsonc theme={null} // Luc's bonus earning with ?expand=tag_assignment,managed_tag_assignment,custom_tag_assignment { "id": "eli_01B...", "object": "earning_line_item", "data": { "amount": 833.33, // ... "managed_tag_assignment": { // Inherited from work assignment (Aurora, Quebec City) "unit": "percentage", "tag_allocations": [ { "tags": [ { "id": "tag_01AURORA...", "object": "tag", "data": { "label": "Aurora" }, }, { "id": "tag_01QC...", "object": "tag", "data": { "label": "Quebec City" }, }, ], "value": 100, "expense_accounting_code": { "id": "ac_5110...", "object": "accounting_code", }, // Aurora Salaries "liability_accounting_code": { "id": "ac_2100...", "object": "accounting_code", }, // Aurora Payroll Liability }, ], }, "custom_tag_assignment": { // User override: Beacon, Quebec City "unit": "percentage", "tag_allocations": [ { "tags": [ { "id": "tag_01BEACON...", "object": "tag", "data": { "label": "Beacon" }, }, { "id": "tag_01QC...", "object": "tag", "data": { "label": "Quebec City" }, }, ], "value": 100, "expense_accounting_code": { "id": "ac_5210...", "object": "accounting_code", }, // Beacon Salaries "liability_accounting_code": { "id": "ac_2200...", "object": "accounting_code", }, // Beacon Payroll Liability }, ], }, "tag_assignment": { // Effective: custom takes precedence over managed "unit": "percentage", "tag_allocations": [ { "tags": [ { "id": "tag_01BEACON...", "object": "tag", "data": { "label": "Beacon" }, }, { "id": "tag_01QC...", "object": "tag", "data": { "label": "Quebec City" }, }, ], "value": 100, "expense_accounting_code": { "id": "ac_5210...", "object": "accounting_code", }, // Beacon Salaries "liability_accounting_code": { "id": "ac_2200...", "object": "accounting_code", }, // Beacon Payroll Liability }, ], }, }, } ```
### 6. Derived statutory withholdings Statutory withholdings derive their tag allocations from the remuneration that generates them. **Marie**: all remuneration is tagged `Project: Aurora`, `Location: Montreal`, so each withholding carries the same single allocation: * Federal tax (\$184.47) * 100% (\$184.47) to `Project: Aurora`, `Location: Montreal` * Provincial tax (\$235.29) * 100% (\$235.29) to `Project: Aurora`, `Location: Montreal` * QPP (\$148.31) * 100% (\$148.31) to `Project: Aurora`, `Location: Montreal` * QPIP (\$10.75) * 100% (\$10.75) to `Project: Aurora`, `Location: Montreal` * EI (\$32.50) * 100% (\$32.50) to `Project: Aurora`, `Location: Montreal` **Luc**: remuneration is \$2,500 (`Project: Aurora`) + \$833.33 (`Project: Beacon`), a 75/25 split. Both carry `Location: Quebec City`. Each withholding derives two allocations at that ratio: * Federal tax (\$325.75) * 75% (\$244.31) to `Project: Aurora`, `Location: Quebec City` * 25% (\$81.44) to `Project: Beacon`, `Location: Quebec City` * Provincial tax (\$350.77) * 75% (\$263.08) to `Project: Aurora`, `Location: Quebec City` * 25% (\$87.69) to `Project: Beacon`, `Location: Quebec City` * QPP (\$200.81) * 75% (\$150.61) to `Project: Aurora`, `Location: Quebec City` * 25% (\$50.20) to `Project: Beacon`, `Location: Quebec City` * QPIP (\$14.33) * 75% (\$10.75) to `Project: Aurora`, `Location: Quebec City` * 25% (\$3.58) to `Project: Beacon`, `Location: Quebec City` * EI (\$43.33) * 75% (\$32.50) to `Project: Aurora`, `Location: Quebec City` * 25% (\$10.83) to `Project: Beacon`, `Location: Quebec City` ### 7. Journal entry rows With Project and Location as journal entry tracking dimensions, each allocation produces its own row. Employer contribution rows are omitted for brevity. | Account | Location | Project | Debit | Credit | | ------------------- | ----------- | ------- | ---------- | ---------- | | Aurora Salaries | Montreal | Aurora | \$2,500.00 | | | Aurora Salaries | Quebec City | Aurora | \$2,500.00 | | | Beacon Salaries | Quebec City | Beacon | \$833.33 | | | Aurora Stat Payable | Montreal | Aurora | | \$611.32 | | Aurora Stat Payable | Quebec City | Aurora | | \$701.25 | | Beacon Stat Payable | Quebec City | Beacon | | \$233.74 | | Net Payroll Payable | | | | \$4,287.02 | # Contractor Payments Source: https://docs.nmbr.co/guides/advanced/contractor-payments Due to their different tax treatments, Contractor payments are handled separately from Employee payroll and off-cycle payroll. Contractors can have two types of payment methods: 1. Direct deposit - Nmbr will deposit the funds to the bank account associated with the contractor. 2. Check - The payroll admin will be responsible for providing the contractor with a check for the amount of the payment. ## Create Contractor Payment Payments to contractors can be added much like earnings are added to an employee. Contractor earnings will not be subject to employment taxes and other statutory withholdings. ## Payment Receipt Once a payroll is submitted, we recommend including a pay stub ("invoice") for the end user to view the debit date, check date, and pay stub details. The payroll receipt should also be available on this final step. # Correction Payrolls Source: https://docs.nmbr.co/guides/advanced/correction-payrolls Correction payrolls allow you to record payroll adjustments without moving money, and are included in ROE calculations Correction payrolls are used to capture payroll adjustments or corrections without triggering any payments. Unlike regular payrolls, no money is moved β€” no employee payments, no contractor payments, and no CRA remittances are generated. Correction payrolls are similar to [historical payrolls](/guides/advanced/historical-payrolls) in that they don't move money and support the same CSV import flow. However, there are key differences: * **Included in ROE calculations**: Correction payroll data is included when generating Records of Employment, unlike historical payroll data which is excluded. * **Supports negative values**: Correction payrolls allow negative amounts on line items, making them suitable for reversals and adjustments. Historical payrolls are typically used to build up year-to-date totals from zero. ## Payroll Setup Start by creating a correction payroll. Note the `type` is set to `"correction"`. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_schedule_id": "axzjqzC5oOZ51h3mqmXK", "type": "correction", "period_start" : "2023-06-01", "period_end" : "2023-06-15", "pay_date": "2023-06-15" }' ``` A new correction payroll will be created, and can have Pay Stub data imported to populate the Payroll. ## Bulk Importing Correction Pay Stubs Nmbr supports bulk importing of correction pay stubs through a CSV file. This uses the same import flow as historical payrolls. There are two types of import templates available: * `preset`: This template includes the line items types configured through a Business Preset. * `all_types`: This template includes all possible line item types. ### Importing through the API Correction pay stubs can be created through the API by uploading a CSV file containing the correction pay stub data. #### Generating the CSV Template Generate the CSV import template by making a GET request. You must specify the template type as either `preset` or `all_types`. ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/payrolls//import?template=preset \ --header 'Authorization: Bearer ' \ --header 'Accept: text/csv' ``` This will return a CSV file that can be filled out with the correction pay stub data. Unlike historical payrolls, values can be negative to represent reversals or adjustments. #### Uploading the CSV File Once the CSV file is filled out, it can be uploaded to the correction payroll using a POST request. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//import \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: multipart/form-data' \ --form 'import_file=@/path/to/your/file.csv' ``` ##### Upload Validation Errors If the `Accept` header is set to `application/json`, validation errors will be returned a JSON object. If the `Accept` header is set to `text/csv`, validation errors will as a CSV that combines the original data with an additional `error` column. This validation CSV can be updated and re-uploaded directly. Note: a CSV will only be returned if the uploaded CSV was well-formed. ### Importing through the Portal Correction pay stubs can also be imported through the Nmbr Portal. Navigate to the Payroll section, select the appropriate Pay Schedule, and then select the Correction Payroll you created earlier. There will be an option to "Import Correction Pay Stubs", which will guide you through the process of uploading a CSV file. Like with the API, you will need to choose between the `preset` and `all_types` templates. ## Approving payrolls Approving the correction payroll will lock in the data. Since correction payrolls do not move money, no payments will be generated upon approval. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls/01HZNX4N7DTJJ9BTV3TSZ46A85/approve \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' ``` ## ROE Impact Approved correction payrolls are included in ROE (Record of Employment) calculations. When a correction payroll's period falls within the window of an ROE pay period, the insurable earnings from the correction are included in the ROE totals. This makes correction payrolls the appropriate choice when adjustments need to be reflected on an employee's ROE. By contrast, historical payrolls are excluded from ROE calculations entirely. # Custom Pay Schedules Source: https://docs.nmbr.co/guides/advanced/custom-pay-schedules Nmbr supports **Custom Pay Schedules** to offer flexible payroll cycles for businesses with non-standard payment needs. > ℹ️ Enabling Custom Pay Schedules > This feature is not enabled by default. To enable it, please contact [support@nmbr.co](mailto:support@nmbr.co). Custom Pay Schedules have the following rules: * **No fixed frequency**: They do not follow a recurring pattern like weekly or monthly schedules. * **Work Assignment required**: Each Employee or Contractor must be assigned a Work Assignment linked to the Custom Pay Schedule. * **Manual payroll creation**: Payrolls and Pay Stubs must be created manually. * **Explicit parameters**: When creating a Payroll, you must specify `period_start`, `period_end`, `original_pay_date`, and `custom_pay_frequency`. * **Overlapping allowed**: Payrolls can overlap in both earning periods and pay dates. * **Strict ordering**: Payrolls must be processed in date order based on `pay_date`. * **Frequency affects taxes**: `custom_pay_frequency` can vary between Payrolls, but may impact the accuracy of tax calculations. ## Creating Payrolls and Pay Stubs Custom Pay Schedules do not auto-generate payrolls, unlike standard pay schedules. Instead, you must create payrolls manually. This allows for greater flexibility in managing payroll cycles, but also requires more attention to detail. When creating a Payroll, you must specify the following parameters: * `period_start` - the first day of the earning period. * `period_end` - the last day of the earning period. * `original_pay_date` - the pay date, ignoring weekends and holidays. * `custom_pay_frequency` - the expected frequency for this payroll. This is used for tax calculations on this Payroll instance. This must be one of `weekly`, `bi-weekly`, `semi-monthly`, or `monthly`. When creating a Payroll, Nmbr will generate the actual `pay_date` based on the `original_pay_date` and the Pay Schedule’s `pay_day_movement_setting`, adjusting for weekends and holidays. Employees and Contractors require a Work Assignment to be assigned to a Pay Schedule, as on a standard Pay Schedule. However, no Pay Stubs are auto-generated on any Payroll in the Custom Pay Schedule, and must be created using the API. ## Pay Rates Work Assignments on a Custom Pay Schedule may have Pay Rates, similar to standard Pay Schedules. Similarly, a Pay Stub will have managed Earning Line Items created for the Pay Rate. However, as Custom Pay Schedules have no standard hours to apply, Earning Line Items will always have a `managed_hours` of `0`. If `custom_hours` is set, the `managed_amount` is calculated using the derived hourly rate and the `custom_hours` value. The hourly rate is determined as: ``` Hourly Rate = annual-salary / 52 / expected_hours_per_week ``` ## Allowances, Reimbursements, Benefits and Deductions Custom Pay Schedules support Allowances, Reimbursements, Benefits and Deductions. These are created in the same way as standard Pay Schedules. However, they can only use a frequency of `once` or `per_payroll`. The `per_month` frequency is not supported. ## Tax Calculation When a Payroll is created, the `custom_pay_frequency` is used to determine the **expected frequency** of this Payroll within the calendar year. To calculate Statutory Withholdings on a Pay Stub, Nmbr must estimate how many payrolls remain in the year. These estimates are based solely on the current Payroll’s attributes, since Custom Pay Schedules do not follow a fixed pattern. The following attributes are estimated using `custom_pay_frequency`, `original_pay_date`, and `pay_date`: * **`regular_periods_count`** – The estimated total number of payrolls in the year for this frequency. * **`period_number`** – The estimated position of this Payroll in the year, regardless of how many payrolls have actually occurred to date. ### Frequency Estimation Rules Each `custom_pay_frequency` uses a different method to estimate the period count: * **`weekly`** – Based on the weekday of `original_pay_date`, counts how many times that weekday occurs in the year (adjusted for pay day movement due to weekends and holidays). * **`bi-weekly`** – Starting from `original_pay_date`, counts every 14-day interval (same weekday) in the year to estimate how many bi-weekly pay days occur. Adjusts for holidays and weekends. * **`semi-monthly`** – `regular_periods_count` is fixed at 24. `period_number` is calculated based on the month and whether the `original_pay_date` falls on or before the 15th (first period) or after (second period). > **Note:** If the `pay_date` is adjusted across year boundaries due to holidays or weekends, `period_number` is calculated relative to the new year. * **`monthly`** – Based on the day of the month in `original_pay_date`, estimates how many remaining payrolls would fall on that same day each month in the year, adjusted for holiday/weekend movement. ## Example To create a Custom Pay Schedule, you can use the following API request: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_schedules \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "business_entity_id": "", "title": "Pay Schedule", "pay_frequency": "custom" }' ``` To create a Payroll on a Custom Pay Schedule, you can use the following API request: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_schedule_id": "", "type": "regular", "period_start": "2025-05-01", "period_end": "2025-05-10", "custom_pay_frequency": "semi-monthly", "original_pay_date": "2025-05-10" }' ``` # Historical Payrolls Source: https://docs.nmbr.co/guides/advanced/historical-payrolls Capturing year-to-date amounts is an important step in the accuracy of your payroll While it’s simpler to switch payroll providers at the beginning of the fiscal year - a point where you have less historical payroll data to deal with - switching payroll providers mid-year does happen. Modern payroll services make the migration process much simpler than the manual processes required by older systems. Nmbr provides support for switching payroll providers mid-year in the form of `historical payrolls`. Historical payrolls are used to capture payroll data from your previous payroll provider, data such as wages paid to date, income tax collected to date, and CPP contributed to date. By capturing at least 1 historical payroll, Nmbr will have the necessary data to calculate your upcoming and future payrolls accurately. ## Payroll Setup Start by creating the shell for a historical payroll. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_schedule_id": "axzjqzC5oOZ51h3mqmXK", "type": "historical", "period_start" : "2023-01-01", "period_end" : "2023-06-01", "pay_date": "2023-06-01" }' ``` A new historical payroll will be created, and can have Pay Stub data imported to populate the Payroll. ## Bulk Importing Historical Pay Stubs Nmbr supports bulk importing of historical pay stubs through a CSV file. This is useful for migrating large amounts of payroll data from a previous provider. There are two types of import templates available: * `preset`: This template includes the line items types configured through a Business Preset. * `all_types`: This template includes all possible line item types. ### Importing through the API Historical pay stubs can be created through the API by uploading a CSV file containing the historical pay stub data. #### Generating the CSV Template Generate the CSV import template by making a GET request. You must specify the template type as either `preset` or `all_types`. ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/payrolls//import?template=preset \ --header 'Authorization: Bearer ' \ --header 'Accept: text/csv' ``` This will return a CSV file that can be filled out with the historical pay stub data. #### Uploading the CSV File Once the CSV file is filled out, it can be uploaded to the historical payroll using a POST request. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//import \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: multipart/form-data' \ --form 'import_file=@/path/to/your/file.csv' ``` ##### Upload Validation Errors If the `Accept` header is set to `application/json`, validation errors will be returned a JSON object. If the `Accept` header is set to `text/csv`, validation errors will as a CSV that combines the original data with an additional `error` column. This validation CSV can be updated and re-uploaded directly. Note: a CSV will only be returned if the uploaded CSV was well-formed. ### Importing through the Portal Historical pay stubs can also be imported through the Nmbr Portal. Navigate to the Payroll section, select the appropriate Pay Schedule, and then select the Historical Payroll you created earlier. There will be an option to "Import Historical Pay Stubs", which will guide you through the process of uploading a CSV file. Like with the API, you will need to choose between the `preset` and `all_types` templates. ## Approving payrolls Approving the historical payroll will lock in the data and give you an accurate foundation for all future payroll runs. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls/01HZNX4N7DTJJ9BTV3TSZ46A85/approve \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' ``` ## Additional Employees A single Pay Schedule can have multiple Historical Payrolls, provided they do not contain conflicting earning periods for any individual employees. If a new Employee, or multiple Employees, are being added to an existing Pay Schedule mid-year, you may create an Historical Payroll to represent those Employees Year-To-Dates before their first `regular` Payroll. # Line Item Adjustments Source: https://docs.nmbr.co/guides/advanced/line-item-adjustments Creating adjustments from previous payrolls Occasionally, payrolls may contain incorrect values that need to be corrected in a future period. Adjustments allow you to issue a correction by creating a new line item that offsets the original error on a future draft pay stub. This is useful for cases like: * A bonus amount was entered incorrectly * An incorrect benefit value was deducted * An earning line item was overstated Adjustments ensure that corrections are processed transparently and legally through the payroll system, and are traceable to the original line item. ## How Adjustments Work To create an adjustment, you specify: * The `source_line_item_id`: the original line item that had an incorrect amount * The `expected_amount`: the amount the line item *should* have been * The `correction_pay_stub_id`: a **draft** pay stub on the same work assignment where the adjustment will appear A new line item is created on the correction pay stub: * It is of the **same type** as the original (e.g. `earning`, `benefit`, `allowance`) * Its value is calculated as the difference between the original amount and the expected amount * If the expected amount is less than the original, the adjustment will be a **negative amount** > ⚠ Adjustments can only be made between pay stubs that belong to the **same work assignment**. ## Adjustment Attributes | Field | Type | Required | Description | | ------------------------ | ------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `correction_pay_stub_id` | string (Nmbr ULID) | βœ… Yes | The ID of the draft pay stub where the correction line item will be added. Must belong to the same work assignment as the original. | | `source_line_item_id` | string (Nmbr ULID) | βœ… Yes | The ID of the original line item to be corrected. Can be any line item type (earning, benefit, deduction, etc.). | | `expected_amount` | number | βœ… Yes | The correct amount the line item *should* have been. The adjustment will be calculated as the difference from this value. | | `is_company_amount` | boolean | ❌ Optional | Only for benefit line items. Set to `true` if the correction is for the company contribution. Defaults to `false`. | | `admin_note` | string | ❌ Optional | Optional note, this is not shared on the Employees pay stub. | ## Example Request ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/adjustments \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "correction_pay_stub_id": "", "source_line_item_id": "", "expected_amount": 1234.50 }' ``` * The new line item is added directly to the correction pay stub and can be reviewed or edited like any other manually added line item. ## Deleting Adjustments Deleting an adjustment will remove the correction line item from the correction pay stub, effectively undoing the correction. Adjustments can only be deleted if the correction pay stub is on a draft payroll. Once the payroll has been approved, adjustments cannot be deleted. > ⚠ Correction line items can not be deleted directly, you must delete the Adjustment to remove the correction line item. ## Viewing Adjustments When requesting a line item of any type, you may `expand` the `source_adjustment` relation to view the Adjustment that created that line item. ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/earning_line_items/?expand=source_adjustment \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` ### Sample Response ```json theme={null} { "id": "ernli_01JV2S0C0FPZ1BS4KVGAR8CJVC", "object": "earning_line_item", "data": { "pay_stub": { "id": "payst_01JN4M4HP7YX74CZC26K0PKT9A", "object": "pay_stub", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/payst_01JN4M4HP7YX74CZC26K0PKT9A" } }, "amount": 500, "managed_amount": null, "custom_amount": 500, // ... "source_adjustment": { "id": "adjst_01JV2S0C06SV5VGNRA3D3KCMKT", "object": "adjustment", "data": { "source_line_item": { "id": "ernli_01JNM9C74KHMEEANYGBWJD78M5", "object": "earning_line_item", "data": { "pay_stub": { "id": "payst_01JN4M4HP38T0TWSJBGAC028WB", "object": "pay_stub", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/payst_01JN4M4HP38T0TWSJBGAC028WB" } }, "amount": 5500, "managed_amount": 5500, "custom_amount": null, "is_managed": true, "line_item_type": "earning", "earning_type": { "id": "salary", "object": "earning_type", "data": { "type": "salary", "label": "Salary", "supported_payroll_types": { "regular": true, "historical": true, "off_cycle": false } }, "links": { "self": null } }, "hours": 82.33, "managed_hours": 82.33, "custom_hours": null, "accrued_vacation_pay": 220, "recurrence": { "id": "payrt_01JN4M4MQFXRFBAMP5QBWM6GBW", "object": "pay_rate", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_rates/payrt_01JN4M4MQFXRFBAMP5QBWM6GBW" } }, "overtime_rate": null, "title": "Location Asst. Manager", "business_preset": null, "source_adjustment": null, "component_settings": { "attributes_locked": false }, "created_at": "2025-03-05T23:13:43.000000Z", "updated_at": "2025-03-05T23:13:43.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/earning_line_items/ernli_01JNM9C74KHMEEANYGBWJD78M5" } }, "correction_line_item": { "id": "ernli_01JV2S0C0FPZ1BS4KVGAR8CJVC", "object": "earning_line_item", "data": { "pay_stub": { "id": "payst_01JN4M4HP7YX74CZC26K0PKT9A", "object": "pay_stub", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/payst_01JN4M4HP7YX74CZC26K0PKT9A" } }, "amount": 500, "managed_amount": null, "custom_amount": 500, "is_managed": false, "line_item_type": "earning", "earning_type": { "id": "salary", "object": "earning_type", "data": { "type": "salary", "label": "Salary", "supported_payroll_types": { "regular": true, "historical": true, "off_cycle": false } }, "links": { "self": null } }, "hours": null, "managed_hours": null, "custom_hours": null, "accrued_vacation_pay": 0, "recurrence": null, "overtime_rate": null, "title": null, "business_preset": null, "source_adjustment": { "id": "adjst_01JV2S0C06SV5VGNRA3D3KCMKT", "object": "adjustment", "links": { "self": "https://sandbox.nmbr.co/services/payroll/adjustments/adjst_01JV2S0C06SV5VGNRA3D3KCMKT" } }, "component_settings": { "attributes_locked": false }, "created_at": "2025-05-12T17:34:43.000000Z", "updated_at": "2025-05-12T17:34:43.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/earning_line_items/ernli_01JV2S0C0FPZ1BS4KVGAR8CJVC" } }, "correction_pay_stub": { "id": "payst_01JN4M4HP7YX74CZC26K0PKT9A", "object": "pay_stub", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/payst_01JN4M4HP7YX74CZC26K0PKT9A" } }, "expected_amount": 6000, "admin_note": null, "created_at": "2025-05-12T17:34:43.000000Z", "updated_at": "2025-05-12T17:34:43.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/adjustments/adjst_01JV2S0C06SV5VGNRA3D3KCMKT" } }, "component_settings": { "attributes_locked": false }, "created_at": "2025-05-12T17:34:43.000000Z", "updated_at": "2025-05-12T17:34:43.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/earning_line_items/ernli_01JV2S0C0FPZ1BS4KVGAR8CJVC" } } ``` # Off-cycle Payroll Source: https://docs.nmbr.co/guides/advanced/off-cycle-payrolls Scheduling off-cycle payments to employees and contractors Sometimes employers need to pay employees or contractors outside the regular schedule of their Pay Schedule. Common reasons for this can include: * Bonuses or Commission not paid on the employee's regular payroll * Corrections for underpayment on an employee's previous Payroll * Payments to terminated employees which may require payment on the date of termination * Contract payments required outside the normal schedule To handle these and other scenarios, Nmbr supports creating an off-cycle payroll. ## Configuring an Off-cycle Payroll Off-Cycle payrolls are more flexible than regular payrolls, but require some information when being created. The payroll requires a valid `pay_date`: * It must not be in the past. * It must not be before the current bank-processing time allowed - e.g. if the current processing speed is 4 days, on Monday (January 1st), the earliest `pay_date` is Friday (January 5th). To correctly calculate taxes, an off-cycle payroll must have a `source_payroll_id`. This Source Payroll must conform to the following rules: * Be from the same Pay Schedule as the off-cycle payroll. * Have a `type` of `regular`. It must not be a `historical` or `off-cycle` payroll. * The `pay_date` of the off-cycle payroll must be in the same calendar year as the `pay_date` on the Source Payroll. You do not define a `period_start` or `period_end` on an off-cycle Payroll, as these are inherited form the Source Payroll. Once an off-cycle payroll has been created, it will have no pay stubs as no employees have yet been assigned to it. You can assign an employee to an off-cycle payroll by attaching their work assignment for that pay schedule to that payroll. An employee cannot be paid on an off-cycle if they do not have a work assignment for that pay schedule. > πŸ“˜ Pay Stub line items > After creating a pay stub on an off-cycle payroll, no earning, reimbursement, benefit or deduction line items are automatically created. All line items must be created directly on the pay stub. > πŸ“˜ Earning line items > An off-cycle pay stub is restricted in what types of earning line items it supports. The line items must be non-periodic types - `retroactive_payment`, `commission`, `bonus_discretionary`, `bonus_non_discretionary`, `lump_sum`, `severance_pay` or `invoice_payment`. After an off-cycle payroll has been set up, with pay stubs and line items, it may be managed in the same way as a [regular payroll](/guides/payroll-fundamentals/payroll-lifecycle). ## Payroll Setup Start by creating the off-cycle payroll. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_schedule_id": "01J571SB1ZRDW9E47E2WRNNSVM", "type": "off_cycle", "pay_date": "2024-02-08", "source_payroll_id": "01J571RQC6XDPSBNNJKM4A38K2" }' ``` A new off-cycle payroll will be created, you will need to create a pay stub for each employee work assignment that you wish to pay on this payroll. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_stubs \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "payroll_id": "01J571ZDJ2X8HTT463VPZ7ER04", "work_assignment_id": "01J5720H39AFZVWY5NZ1GYVPAW", "note": "Off-cycle payroll note" }' ``` ## Running the Off-cycle Payroll An off-cycle can be approved at any time relative to its source payroll, provided the source payroll is not a future payroll (beyond the next scheduled payroll in the pay schedule). The off-cycle payroll can be approved before or after the source payroll is approved, and paid before or after the source payroll is paid. If an off-cycle payroll is approved before its source payroll, the method in which the statutory withholdings are calculated will be different than if the source payroll has already been approved. See the section on [Statutory withholdings](#statutory-withholdings) for more information. ## Statutory Withholdings Nmbr supports two methods for calculating statutory withholdings on off-cycles: the Combined Method (used when the source payroll is approved first) and the Standalone Method (used when the off-cycle is approved first). > πŸ“˜ Additional tax is not withheld on off-cycles > If an employee asks for extra income tax to be withheld each pay (the additional tax on their federal TD1, or the Quebec additional amount), that extra applies on regular payrolls only. An off-cycle pay stub shows no additional tax, even when the employee has elected one. ### Combined Method Determine the difference between the source statutory withholdings and the combined statutory withholdings, and apply that difference to the off-cycle payroll if applicable. * The total taxable remuneration from both the source payroll and the off-cycle payroll are combined. * Statutory withholdings are calculated on the combined remuneration. * As this is a recalculation which takes into account the regular payroll, any credits or exemptions that apply are taken into account. * The statutory withholdings on the off-cycle are the difference between the source statutory withholdings and the combined statutory withholdings. For example, if an employee receives additional pensionable earnings in an off-cycle payroll, the system will recalculate the total CPP contributions as if the earnings were included in the original payroll. The off-cycle payroll will then withhold only the difference between the new total and the original deductions, preventing over- or under-contributions. ### Standalone Method When an off-cycle payroll is approved before its source payroll, the standalone method is used to calculate statutory withholdings. * Statutory withholdings are calculated only on the taxable remuneration in the off-cycle payroll. * Credits and exemptions are not taken into account, as they are expected to be applied in the source payroll’s calculation. * When the source payroll is later approved, the off-cycle will be used as year-to-date data. # Presets Source: https://docs.nmbr.co/guides/advanced/presets Define reusable sets of properties for entities ## Introduction Business Presets are a Nmbr feature that allow you to * define a reusable set of properties for entities including allowances, deductions, earnings, employee and employer benefits, reimbursements, pay rates, overtime rates, and line items * apply those properties to many entities * ensure the values of those properties can *only* be changed through the preset and not through the entity * group line items consistently for reporting purposes ## Supported Properties Business Presets currently support the following properties: * `name`: The name of the preset. The preset name is displayed in the component when listing or selecting presets. The name may also be displayed on pay stubs or reports when line items are grouped by preset, as the line items may have different `title` values. * `type`: The type of entity the preset can be applied to. > `type` must be one of > > * `earning` (for earnings, pay rates, overtime rates, and earning line items) > * `allowance` > * `employee_benefit` > * `employer_benefit` > * `deduction` > * `reimbursement` * `subtype`: The sub-type of entity the preset can be applied to. > If not set, the preset can be applied to any recurrence or line item of the specified `type`. If set, `subtype` must be one of the type values for the specified `type`. For example: > > * If `type` is `earning`, `subtype` must be an [earning type](/api-reference/earning-types/list-earning-types) (`salary`, `wage`, etc) > * If `type` is `allowance`, `subtype` must be an [allowance type](/api-reference/allowance-types/list-allowance-types) (`taxable_cash_allowance`, `automobile_and_motor_vehicle`, etc). > * etc > > ⚠️ Pay rates and earning line items have different type values for hourly wages. Pay rates use the value `hourly` while earning line items use `wage`. Presets use the earning line item type, i.e. `wage`. > > ⚠️ Overtime rates don't have their own `type`. An overtime rate's preset must be of the same type as the overtime rate's pay rate. * `label`: The label to apply to the entity. * `remittance_account_id`: The remittance account to sync to the entity. > ⚠️ Only benefit and deduction types have remittance accounts. Other types will ignore this property. * `expense_accounting_code_id` and `liability_accounting_code_id`: The accounting codes to sync to the entity. ## Usage ### Creating Business Presets Business Presets are created as follows: ``` POST /services/payroll/business_presets { "type": "allowance", "subtype": "automobile_and_motor_vehicle", "name": "Car Allowance (2025 mid-year)", "label": "Car Allowance", ...other Business Preset properties... } ``` ### Creating entities with Business Presets A new entity can be created with a Business Preset by including the `business_preset_id` property in the create request. For example, when creating an allowance: ``` POST /services/payroll/allowances { "business_preset_id": "", ...other allowance properties... } ``` Any property values set on the Business Preset will be copied to the newly-created entity. ### Importing hours with a Business Preset To target a preset while importing hours, send its ID as `business_preset_id` on the earning entry in a `POST /payrolls/{payroll}/hours` request. The preset must be an earning preset that is compatible with the entry's earning type. See [Importing Hours](/guides/payroll-fundamentals/importing-hours) for the request shape and matching behaviour. ### Adding a Business Preset to an existing entity An existing entity can have a Business Preset added to it by including the `business_preset_id` property in an update request. For example, when updating an allowance: ``` PUT /services/payroll/allowances/alw_01K2Q0T546RAHGJHV9WNWNE4GW { "business_preset_id": "", } ``` Any property values set on the Business Preset will be copied to the updated entity, overwriting the existing values for those properties on the entity. ### Removing a Business Preset from an existing entity An existing entity can have a Business Preset removed from it by including the `business_preset_id` property in an update request with the value `null`. For example, when updating an allowance: ``` PUT /services/payroll/allowances/alw_01K2Q0T546RAHGJHV9WNWNE4GW { "business_preset_id": null, } ``` Any properties values previously copied from the Business Preset will remain on the updated entity, but will become editable and will no longer be synced from the Business Preset. ### Updating Business Presets Business Presets are updated as follows: ``` PUT /services/payroll/business_presets/ { "label": "Vehicle Allowance", ...other Business Preset properties... } ``` ℹ️ The `type` and `subtype` properties can't be updated as they could change the types of entities that can be associated with the preset, invalidating entities already associated with the Business Preset. The updated values will cascade down from the Business Preset to the entities associated with it automatically. ℹ️ Line items on non-draft payrolls will **not** be updated as this would change historical pay stubs and remittances. All updated values will cascade down from the Business Preset to associated entities, keeping the entities in-sync with the Business Preset. ### Deleting Business Presets Business Presets are deleted as follows: ``` DELETE /services/payroll/business_presets/ ``` By default, deleting a Business Preset will keep any values synced from the Business Preset to associated entities. An optional `keep_existing_values` query string parameter can be supplied to control this behavior. | `keep_existing_values` | Behavior | | ---------------------- | ------------------------------------------------------------------------ | | `all` (default) | Keep all existing values on associated entities. Don't clear any values. | | `none` | Don't keep any existing values on associated entities. Clear all values. | After the Business Preset is deleted, previously associated entities will be fully editable. # Preview Mode Source: https://docs.nmbr.co/guides/advanced/preview-mode When creating a new Business Entity in Nmbr, employers can set up the entity in `Preview` mode. This allows for the safe simulation of payroll operations without triggering any actual financial transactions. ## Key Features of Preview Mode * **No Financial Operations:** While in Preview mode, no bank transactions are created and no money is remitted. * **Full Functionality:** Employers can set up Work Assignments, Pay Schedules, Benefits, Deductions, Allowances, and Reimbursements normally. * **Payroll Processing:** Regular payrolls can be approved, while Once-off and Historical payrolls can be created and processed. Approved payrolls are automatically marked as paid to facilitate the calculation of statutory withholdings on future payrolls, despite no actual payment transactions. Because the payroll is marked paid right away, it never sits in the `approved` or `processing` state. That means you can't move it back to draft (unapprove) in preview mode. * **Employee Data Import:** Employers can import employee year-to-date information during the setup of historical payrolls. ## Transitioning Out of Preview Mode When transitioning out of `Preview` mode: * **Data Preservation:** All Pay Schedules, Work Assignments, Deductions, and Allowances are retained. * **Payroll Adjustment:** You will have the option to convert paid payrolls to historic payrolls, preserve draft line items, and preserve draft off-cycles. * **Historical Data:** Historical payrolls and pay stubs are preserved with the existing imported year-to-date data intact. This setup allows for comprehensive testing and verification of payroll setup before committing to live financial transactions, ensuring accuracy and confidence in payroll management. ## Creating a Preview mode Business Entity example To create a Business Entity in `preview` mode, set the attribute `in_preview` to `true`. ```bash theme={null} curl --location --request POST 'https://sandbox.nmbr.co/services/payroll/business_entities' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "in_preview": true, "business_number": "123456782RP0001", "name": "Business Inc", "legal_name": "Business Inc", "address_line_1": "2020 Yates St", "city": "Victoria", "province_code": "BC", "country_code": "CA", "postal_code": "V8S 1Z8", "contact_name": "Mary Jayne", "contact_area_code": "250", "contact_phone_number": "8097625" }' ``` # EI Premium Reduction Source: https://docs.nmbr.co/guides/canada/ei-rate-reduction Applying a reduced employer EI multiplier to a CRA remittance account Employers who provide a qualifying short-term disability plan can apply to the Canada Employment Insurance Commission for a reduced Employment Insurance (EI) premium rate. The reduction lowers the employer's share of EI. The employee's share is unchanged. Record an approved reduction as a [Tax Property](/guides/payroll-fundamentals/tax-properties) on the business's CRA remittance account. Nmbr then uses it on every pay stub that remits EI through that account. *** ## How the reduction is applied Employer EI is a multiple of the employee's EI premium for the same period. Without a reduction, Nmbr uses the CRA's standard employer rate, which is 1.4 times the employee rate. A reduction replaces the 1.4 multiplier with the lower one the Commission granted. Nothing else in the calculation changes. For a pay stub with \$166.00 of employee EI premiums: | Employer multiplier | Employer EI premium | | :------------------ | :------------------ | | 1.4 (standard) | \$232.40 | | 1.2 (reduced) | \$199.20 | The employee pays \$166.00 either way, so net pay is the same. Only the employer cost, and the amount remitted to the CRA, change. The multiplier must be between 1 and 1.4. The business needs written confirmation of its rate from the Commission before you set one. See the [EI Premium Reduction Program](https://www.canada.ca/en/employment-social-development/programs/ei/ei-list/ei-employers/premium-reduction-program.html) for eligibility and how to apply. *** ## The tax property The multiplier is held in the `ca::ei_premium_reduction` Tax Property. Its `value` is a single number. The owner must be a remittance account whose `account_provider` is `ca_cra`. Any other owner is rejected on `owner_id` with `EI Premium Reduction owner must be CRA account`. Retrieve the template from the [Tax Property Templates](/api-reference/tax-property-templates/retrieve-a-tax-property-template) endpoint to confirm the format and validation: **Request** ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/tax_property_templates/ca::ei_premium_reduction \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "id": "ca::ei_premium_reduction", "object": "tax_property_template", "data": { "type": "ca::ei_premium_reduction", "label": "CRA EI Premium Reduction", "format": "numeric", "options": null, "allow_concurrent": false, "feature": "onboarding", "nullable": true, "structure": null, "validation": { "min": 1, "max": 1.4 } }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/tax_property_templates/ca::ei_premium_reduction" } } ``` *** ## Applying a reduction Most businesses have one CRA remittance account, created as part of [Tax Agency Configuration](/guides/payroll-fundamentals/tax-agency-configuration). Retrieve it with the [Remittance Accounts](/api-reference/remittance-accounts/list-remittance-accounts) endpoint, filtered to the business entity. You can set the multiplier when you create the account, or add it later. ### On a new account Include the property in the `tax_properties` array on the [Create a Remittance Account](/api-reference/remittance-accounts/create-a-remittance-account) request. This array is only accepted on create. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/remittance_accounts \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "business_entity_id": "", "account_provider": "ca_cra", "label": "CRA Payroll Account", "account_identifier": "123456782RP0001", "tax_properties": [ { "type": "ca::ei_premium_reduction", "value": "1.2", "effective_from": "2026-01-01" } ] }' ``` ### On an existing account Send the CRA remittance account's ID as `owner_id` to the [Create a Tax Property](/api-reference/tax-properties/create-a-tax-property) endpoint. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "type": "ca::ei_premium_reduction", "value": "1.2", "effective_from": "2026-01-01" }' ``` `effective_from` is required. Set it to the first day the confirmed rate applies, which is January 1 for a rate granted for a calendar year. *** ## Which pay stubs use the reduction Nmbr resolves a CRA remittance account for each work assignment from its remittance account enrollments, using the payroll's `pay_date`. Work assignments enrolled in the account use that account's multiplier. A work assignment with no CRA enrollment falls back to the business entity's CRA account when the business entity has exactly one. If a business has more than one CRA account and the reduction applies to more than one, create a Tax Property on each account. *** ## Updating the rate The Commission confirms a reduced rate for a calendar year, so the multiplier changes when a new rate is granted for the following year. `allow_concurrent` is `false` for this template, so an account holds one multiplier at a time. To move to a new rate, set `effective_to` on the current Tax Property to the last day the old rate applies, then create a new one with an `effective_from` after that date. A Tax Property cannot be ended before the `pay_date` of the most recent payroll that used it. The `earliest_valid_effective_to` attribute on the Tax Property gives you that floor. See [Ending a Tax Property](/guides/payroll-fundamentals/tax-properties#ending-a-tax-property) for the full rules. Once a payroll that used the property is approved, `is_editable` becomes `false` and only `effective_to` and `note` can be changed. Correcting a multiplier after that means ending the property and creating a replacement. *** ## Removing the reduction Set `effective_to` on the Tax Property to the last day the reduced rate applies. Payrolls with a `pay_date` after that date use the standard 1.4 employer rate again. *** ## Verifying what was applied Employee and employer EI for a pay stub are in the [Statutory Withholding Line Items](/api-reference/statutory-withholding-line-items/list-statutory-withholding-line-items) for the payroll. The employer amount carries the reduction; the employee amount does not. The `ei-cpp-balance` [report](/guides/payroll-fundamentals/payroll-reporting) has a CRA EI Premium Reduction column holding the multiplier in effect for the account, next to the employee and employer EI totals. For Quebec payrolls, use `ei-qpp-qpip-balance`. # Employer Payroll Tax (EPT / EHT) Source: https://docs.nmbr.co/guides/canada/employer-health-tax In some Canadian provinces, employers are required to pay Employer Payroll Taxes (EPT) based on their payroll. These taxes help fund provincial health services and are calculated based on a business's total payroll. The Nmbr API allows you to review the calculated EPT for each payroll, as well as override the default settings used in the calculation. Nmbr currently supports EPT calculation for the following provinces: * British Columbia - [EHT](https://www2.gov.bc.ca/gov/content/taxes/employer-health-tax/employer-health-tax-overview) * Manitoba - [HE Levy](https://www.gov.mb.ca/finance/taxation/taxes/payroll.html) * Newfoundland and Labrador - [HAPSET](https://www.gov.nl.ca/fin/tax-programs-incentives/business/education/) * Ontario - [EHT](https://www.ontario.ca/document/employer-health-tax-eht) * Quebec - [HSF (Health Services Fund)](https://www.revenuquebec.ca/en/businesses/source-deductions-and-employer-contributions/calculating-source-deductions-and-employer-contributions/employer-contributions-to-the-health-services-fund/) Note that EPT is calculated based on the best available information at the time of payroll. However, final EPT obligations calculated at the end of the year may differ due to changes in payroll, such as adjustments in headcount, total remuneration, or the provinces where employees work. To support more accurate calculations throughout the year, Nmbr allows you to override default assumptions with custom values that better reflect your expected annual situation. ## EPT calculation EPT is generally calculated per payroll and per province. The following attributes are used to determine the EPT: * **Payroll remuneration** – The total amount of eligible remuneration in the payroll, based on each work assignment's current province of employment. * **Annual remuneration** – The expected annual remuneration for the business entity in the province. By default, this is forecasted based on year-to-date earnings and the current payroll. * **Exemption amount** – The amount of payroll remuneration exempt from EPT. By default, this is set to the provincial exemption amount, adjusted for the expected annual remuneration. * **EPT rate** – The applicable rate based on the province and the expected annual remuneration. This rate is used to calculate the EPT on the payroll remuneration. If no overrides are provided, Nmbr uses real-time forecasting based on payroll data to estimate these values. ## Overriding EPT settings Because payroll can change significantly over the course of the year, the EPT calculation is designed to adapt based on current information. However, if you already know that the default assumptions won't reflect your actual year-end situation β€” for example, if you expect major hiring in the coming months β€” you can provide override values using [Tax Properties](/guides/payroll-fundamentals/tax-properties). The following tax properties are available to override EPT calculations by province: * British Columbia: `ca::bc::eht` * Manitoba: `ca::mb::eht` * Newfoundland and Labrador: `ca::nl::eht` * Ontario: `ca::on::eht` * Quebec: `ca::qc::eht` Each of these properties accepts a JSON object with the following attributes: ```json theme={null} { "annual_remuneration": 1200000, "exemption": 500000, "rate": 2.1 } ``` * `annual_remuneration` – The expected annual remuneration for the business in that province. * `exemption` – The amount of remuneration that should be exempt from EPT. * `rate` – The EPT rate to apply, expressed as a percentage. Each value is optional. If you only need to override one field (e.g., exemption), you can omit the others. > **Note for Quebec:** The `exemption` field is not applicable for Quebec's HSF. Only `annual_remuneration` and `rate` should be used. > Note: Overrides take precedence over forecasted values. If set, they will be used directly in the EPT calculation.
Sample Request To create a tax-property to manage EPT calculations, you can use the following request: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "effective_from": "2025-01-01", "type" : "ca::bc::eht", "value" : { "annual_remuneration" : 3150000, "exemption" : 100000, "rate" : 1.8 } }' ```
## EPT reporting The approved EPT amount for each payroll is available in the `employer-health-tax` [report](/guides/payroll-fundamentals/payroll-reporting). When the report is generated, Nmbr will re-calculate the EPT using the most current payroll information. This recalculation does **not** affect the originally calculated EPT amount, but it allows you to review expected EPT obligations for reconciliation or audit purposes. # Indigenous Employees Tax Exemptions Source: https://docs.nmbr.co/guides/canada/indigenous-employees Managing tax exemptions for Indigenous employees Nmbr supports payroll configurations for employees who are partially or fully tax-exempt under section 87 of the *Indian Act*. These exemptions apply when some or all of an employee’s income is considered β€œsituated on a reserve,” using the CRA’s connecting-factors framework. Exemptions are configured using Tax Properties assigned to an employee’s Work Assignment. ## Configuring the exemption Create a Tax Property with the type `ca::first_nation_exemptions`. The `value` object accepts the following fields: * **`exemption_percentage`** (numeric, required) The percentage of employment income that is exempt from income tax. For example, `50` means 50% exempt and 50% taxable. * **`pension_opt_in`** (boolean, optional, default `false`) If `true`, the employee contributes CPP/QPP on **100%** of earnings, including the exempt portion. If `false`, CPP/QPP pensionable earnings are **pro-rated** using the exemption percentage, consistent with CRA PDOC behaviour. ### Example ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "effective_from": "2025-01-01", "type": "ca::first_nation_exemptions", "value": { "exemption_percentage": 50, "pension_opt_in": false } }' ``` ## How Statutory Withholdings are calculated ### Income tax (Federal and Provincial) * Nmbr reduces taxable employment income according to the exemption\_percentage. * Example: if gross earnings are $4,000 and the exemption is 50%, taxable income for source-deduction purposes becomes $2,000. ### CPP/QPP pensionable earnings *Default (pension\_opt\_in = false)* CPP/QPP pensionable earnings are pro-rated using the same exemption percentage. Example: $4,000 Γ— 50% = $2,000 pensionable earnings. *Pension Opt-In (pension\_opt\_in = true)* Pension contributions are calculated on the full earnings amount. Example: $4,000 β†’ $4,000 pensionable earnings. # Record of Employment (ROE) Source: https://docs.nmbr.co/guides/canada/record-of-employment Generate, validate, and submit ROEs to Service Canada The Nmbr API generates ROEs, validates them, and submits them to Service Canada. A Record of Employment (ROE) is the form an employer issues when an employee quits, is laid off, or takes an unpaid leave. If pay stops, for any reason, an ROE is due. Service Canada uses it to work out the employee's Employment Insurance (EI) benefits: whether they qualify, how much, and for how long. > For the full rules, including what each block means, see [Service Canada's ROE guide for employers](https://www.canada.ca/en/employment-social-development/programs/ei/ei-list/reports/roe-guide.html). ## ROEs are forms An ROE is a form. Read the [Forms guide](/guides/payroll-fundamentals/forms) for how form types describe their fields, and how to create, read, update, and validate a form. This page covers what's specific to ROEs. Retrieve the definition with the [Retrieve a form type](/api-reference/form-types/retrieve-a-form-type) endpoint and build your editing UI from it. The fields carry the ROE-specific details, such as the separation codes on Block 16: **Request** ```json theme={null} # GET /services/payroll/form_types/roe ``` **Response (truncated)** ```json theme={null} { "id": "roe", "object": "form_type", "data": { "type": "roe", "label": "Record of Employment", "version_year": 2026, "version_month": "august", "groups": { "employment_dates": "Employment Dates & Final Pay Period", "reason_recall_contact": "Reason, Recall & Contact" }, "fields": [ { "key": "block_16_separation_code", "label": "Separation Code (Block 16)", "type": "select", "required": true, "readonly": false, "group": "reason_recall_contact", "options": { "A00": "(A00) Shortage Of Work Or End Of Contract", "E00": "(E00) Quit", "M00": "(M00) Dismissal" } } ] } } ``` ## Generating ROEs Generate ROEs with the [Generate forms](/api-reference/form-types/generate-forms) endpoint. Send a `roes` array, where each entry describes one ROE: the employee, the work assignments it covers, and its date window. One request can generate many ROEs. **Request** ```json theme={null} # POST /services/payroll/form_types/roe/generate { "roes": [ { "employee_id": "emp_01H7M9X2QV4N", "work_assignment_ids": ["wrkas_01HX3F7T8B2D"], "first_day_worked": "2026-01-06", "last_day_for_which_paid": "2026-07-31", "separation_code": "A00", "expected_recall_code": "N" } ] } ``` Each ROE accepts: * `employee_id` (required): the employee the ROE is for. * `work_assignment_ids` (required): the work assignments the ROE covers. They must belong to the same employee and the same business entity. * `first_day_worked` (required): Block 10. The first day the employee worked and earned insurable pay. If they had an earlier ROE, this is the first day worked since that ROE, not their hire date. Format `YYYY-MM-DD`. * `last_day_for_which_paid` (required): Block 11. The last day the employee was paid insurable earnings for. Usually their last day of work, but paid vacation or sick days at the end of employment push it later. Must be on or after `first_day_worked`. Format `YYYY-MM-DD`. * `separation_code` (optional): Block 16, the reason for issuing the ROE. For example, `A00` for shortage of work or end of contract, `E00` for a quit. See [Service Canada's ROE guide](https://www.canada.ca/en/employment-social-development/programs/ei/ei-list/reports/roe-guide.html) for the full list. * `expected_recall_code` (optional): Block 14. One of `Y` (returning), `N` (not returning), or `U` (unknown). * `expected_recall_date` (optional): Block 14. Format `YYYY-MM-DD`. `first_day_worked` and `last_day_for_which_paid` bound the ROE. The pay periods, insurable earnings and hours, and the final pay period ending date are all derived from the payrolls between them. `effective_date` (optional, format `YYYY-MM-DD`) applies to every ROE in the request and sets which ROE version the forms use. It defaults to today. Generation runs in the background, so the endpoint returns an async task instead of the forms themselves. **Response** ```json theme={null} { "id": "task_01HZ9R4M6K0P", "object": "async_task", "data": { "type": "form_generation", "status": "processing", "completed_at": null, "results": [] } } ``` ### Tracking generation Follow the work in one of two ways: poll the [Retrieve an async task](/api-reference/async-tasks/retrieve-an-async-task) endpoint, or listen for the `async_task_completed` [webhook](/api/overview/webhook-structure), which fires when the task finishes, whether it succeeded or failed. The task starts as `processing` and moves to `completed` once every ROE is created. A failed run moves to `error` instead and removes any ROEs it had already created, leaving `completed_at` as `null`. Fetch the task on every webhook and check `status` before you act on the results. **Request** ```json theme={null} # GET /services/payroll/async_tasks/task_01HZ9R4M6K0P ``` **Response** ```json theme={null} { "id": "task_01HZ9R4M6K0P", "object": "async_task", "data": { "type": "form_generation", "status": "completed", "completed_at": "2026-08-07T18:42:11Z", "results": [ { "id": "form_01HZ9RBC72W8", "object": "form", "status": "draft" } ] } } ``` Each entry in `results` is a generated ROE. The forms are created as drafts with their fields already populated from the employee's payroll data. Retrieve a form with the [Retrieve a form](/api-reference/forms/retrieve-a-form) endpoint to read or edit it before validation. If a single ROE fails to generate, its entry carries an `error` key while the others succeed. The task still completes. ## Insurable earnings by pay period An ROE breaks insurable earnings down by pay period: each period has `pp{n}_insurable_earnings`, `pp{n}_insurable_hours`, and `pp{n}_period_end_date` fields, which the generator fills from payroll data. Periods run newest to oldest: `pp1` is the final pay period, and its ending date is Block 12. The Block 15A and 15B totals are derived from the per-period values, so you don't set them. ## Validation Validate an ROE's fields with the [Validate a form](/api-reference/form-types/validate-a-form) endpoint before submission. Send the form's `effective_date` and the fields you want to check. The full list of fields you can validate comes from the [Retrieve a form type](/api-reference/form-types/retrieve-a-form-type) endpoint, under the `fields` key. **Request** ```json theme={null} # POST /services/payroll/form_types/roe/validate { "effective_date": "2026-08-07", "block_10_first_day_worked": "2026-01-06", "block_11_last_day_for_which_paid": "2026-07-31", "block_16_separation_code": "A00", "pp1_insurable_earnings": 0.0, "pp2_insurable_earnings": 1840.0, "pp3_insurable_earnings": 1840.0 } ``` **Response** ```json theme={null} { "data": { "errors": { "pp1_insurable_earnings": ["pp1_insurable_earnings cannot be 0"] } } } ``` ## Submission Submit an ROE with the [Submit a form](/api-reference/forms/submit-a-form) endpoint. The ROE must be valid to submit: a form with outstanding errors is refused. Nmbr files submitted ROEs with Service Canada through ROE SAT (Secure Automated Transfer), Service Canada's electronic filing channel for payroll service providers. ### Letters of Agreement Filing on an employer's behalf requires their permission: a Letter of Agreement (LOA) signed by the employer, authorizing Nmbr to issue their ROEs. Once the employer's LOA is on file, their ROEs are managed: submission hands them to Nmbr to file. Without a signed LOA, submission marks the ROE `done` but nothing is sent to Service Canada. The XML export (the [Retrieve a form](/api-reference/forms/retrieve-a-form) endpoint with an `Accept: application/xml` header) produces the file to upload in ROE Web. ### The lifecycle A managed ROE moves through these statuses: * `draft`: editable and validatable. * `processing`: queued for transmission to Service Canada. No longer editable. * `submitted`: transmitted to Service Canada, response pending. * `done`: accepted and filed. The [employee copy](#the-employee-copy-pdf) becomes available. Poll the form to follow it through the lifecycle. A managed ROE cannot be exported as XML, because Nmbr handles the filing. ### Serial numbers You never set serial numbers. Block 1 (the ROE's own serial) and Block 2 (the serial of the ROE it amends) are read-only, and values sent for them are ignored. Nmbr assigns Block 1 when a managed ROE is submitted, and fills Block 2 when you amend. ### Amending a filed ROE A filed ROE can't be edited or cancelled, only amended. Service Canada expects an amendment when the original needs to be changed, corrected, or updated (for example, extra separation money is paid after filing), when the original was issued in error, or when Service Canada requests one. Amend a `done` ROE with the [Amend a form](/api-reference/forms/amend-a-form) endpoint. **Request** ```json theme={null} # POST /services/payroll/forms/form_01HZ9RBC72W8/amend ``` The response is a new draft ROE that starts as a copy of the original, ready to edit. Block 2 carries the serial number of the ROE it replaces, and the amendment takes a fresh Block 1 serial when you submit it. It then moves through the same lifecycle as any managed ROE. The original stays `done` and points to the amendment through its `superseding_form` field; the amendment points back through `source_form`. An amendment is a complete replacement, not a diff. Service Canada swaps out the original wholesale, so every field is filed again, not just the ones that changed. Only ROEs Nmbr filed for you can be amended this way. An ROE filed manually must be corrected in ROE Web, and trying to amend one returns a `not_amendable` error. ### The employee copy (PDF) Once a managed ROE reaches `done`, retrieve the employee's copy with the [Retrieve a form](/api-reference/forms/retrieve-a-form) endpoint and an `Accept: application/pdf` header. The PDF renders in the employee's preferred language. # Statutory Holiday Pay Source: https://docs.nmbr.co/guides/canada/statutory-holiday-pay Set up and calculate statutory holiday pay In Canada, employers may be required to pay employees for statutory holidays. The amounts paid are calculated based on the employee's earnings in a period leading up to the holiday. Each province and territory has its own rules for calculating statutory holiday pay, including: * Which holidays are statutory holidays and when they are observed. For example, Boxing Day is a statutory holiday in Ontario but not Alberta. * How many days or weeks of earnings to include when calculating statutory holiday pay. For example, British Columbia considers 30 days of earnings, Yukon considers 2 weeks of earnings, Quebec considers 4 weeks of regular earnings and 12 weeks of commission, etc. * Which earning types are included in the statutory holiday pay calculation. For example, not all provinces include bonuses. ## Enabling Statutory Holiday Pay To enable statutory holiday pay, you must create a `ca::statutory_holiday_pay` tax-property for each work-assignment using the [`tax_properties` API](/guides/payroll-fundamentals/tax-properties). The `value` of the tax-property is an object that may include any of the following optional properties: * `calculate_entitlement` (boolean, optional) - Whether to calculate the entitlement amount (`true`) or default to a \$0 amount that can be overridden by the end user (`false`). Defaults to `false`. * `calculation_strategy` (enum, optional) - Which strategy to use for calculating the entitlement amount. Defaults to `provincial_rules_only`. Must be one of: * `provincial_rules_only`: Calculate the entitlement amount using the work assignment's Province of Work (POW)'s rules. See [Provincial Rules Calculations](#provincial-rules-calculations) below. * `hours_only`: Calculate the entitlement amount as a fixed number of hours at one of the work assignment's hourly pay rates. See [Fixed Hours Calculations](#fixed-hours-calculations) below. * `provincial_rules_or_hours`: Calculate the entitlement amount using both strategies and use whichever amount is greater. This lets the employer guarantee the employee a minimum number of paid hours per holiday while still paying out more when provincial rules require it (for example, when commissions push the provincial amount above the minimum). ### Provincial Rules Properties The following properties are allowed only when `calculation_strategy` is `provincial_rules_only` (the default) or `provincial_rules_or_hours`. Sending them when `calculation_strategy` is `hours_only` returns a validation error. * `override_rule_set` (string, optional) - Override the work assignment's Province of Work and use a different province or territory's rules for statutory holiday pay. * `override_date_basis` (enum, optional) - Override the selected province or territory's date basis for calculating statutory holiday pay. Must be one of: * `before_holiday_day`: Calculates statutory holiday pay based on included earnings over a period ending the day before the holiday is observed. * `before_holiday_week`: Calculates statutory holiday pay based on included earnings over a period ending the day before the holiday week begins. The beginning of the holiday week isn't necessarily the beginning of the calendar week the holiday is in. Nmbr calculates the beginning of the holiday week by taking the pay period start date and adding whole weeks until the date is less than a week before the holiday. This helps reduce proration (see below) for provinces that look at earnings over a period of weeks rather than days. * `before_holiday_pay_period`: Calculates statutory holiday pay based on included earnings over a period ending the day before the holiday pay period begins. ### Fixed Hours Properties The following properties are required when `calculation_strategy` is `hours_only` or `provincial_rules_or_hours`. Sending them under any other strategy (including the default `provincial_rules_only`) returns a validation error. * `hours` (number, required) - The number of hours to pay the employee for each statutory holiday. Must be between 0 and 40. * `pay_rate` (enum, required) - Which of the work assignment's hourly pay rates to use when calculating the fixed-hours amount. A work assignment may have multiple hourly pay rates effective on the holiday's observed date, so this selector specifies how to pick one. Must be one of: * `highest_rate`: The pay rate with the highest hourly `rate`. * `highest_expected_hours_per_week`: The pay rate with the highest `expected_hours_per_week`. * `highest_expected_weekly_amount`: The pay rate with the highest expected weekly amount (`rate` Γ— `expected_hours_per_week`). * `earliest_effective_from`: The pay rate with the earliest `effective_from` date. * `latest_effective_from`: The pay rate with the latest `effective_from` date. Ties are broken by the highest `rate`, then the earliest `effective_from` date, then the earliest `id`. If the work assignment has no hourly pay rate effective on the holiday's observed date, the fixed-hours amount is \$0. ### Examples **Example 1:** Enable statutory holiday pay using the work assignment's Province of Work's rules for calculating statutory holiday pay, defaulting to a \$0 amount. ``` "value": {} ``` **Example 2:** Enable statutory holiday pay using the work assignment's Province of Work's rules for calculating statutory holiday pay, calculating the entitlement amount. ``` "value": { "calculate_entitlement": true } ``` **Example 3:** Enable statutory holiday pay using the work assignment's Province of Work's rules for calculating statutory holiday pay, calculating the entitlement amount, but calculating it based on included earnings over a period ending the day before the holiday pay period begins instead of the default date basis for the province/territory: ``` "value": { "calculate_entitlement": true, "override_date_basis": "before_holiday_pay_period" } ``` **Example 4:** Enable statutory holiday pay using Ontario's rules for calculating statutory holiday pay, calculating the entitlement amount: ``` "value": { "calculate_entitlement": true, "override_rule_set": "ON" } ``` **Example 5:** Enable statutory holiday pay using Ontario's rules for calculating statutory holiday pay, calculating the entitlement amount, but calculating it based on included earnings over a period ending the day before the holiday *pay period* begins instead of the day before the holiday *week* begins (the default date basis for Ontario): ``` "value": { "calculate_entitlement": true, "override_rule_set": "ON", "override_date_basis": "before_holiday_pay_period" } ``` **Example 6:** Pay a fixed 8 hours of statutory holiday pay at the work assignment's highest-rate pay rate, regardless of provincial rules: ``` "value": { "calculate_entitlement": true, "calculation_strategy": "hours_only", "hours": 8, "pay_rate": "highest_rate" } ``` **Example 7:** Guarantee the employee at least 8 hours of statutory holiday pay at their highest-rate pay rate, but pay more if the work assignment's Province of Work's rules calculate a greater amount (for example, when commissions are included): ``` "value": { "calculate_entitlement": true, "calculation_strategy": "provincial_rules_or_hours", "hours": 8, "pay_rate": "highest_rate" } ``` Statutory holiday pay will not be calculated for any work-assignment unless a valid tax-property is configured. ## Fixed Hours Calculations When `calculation_strategy` is `hours_only` or `provincial_rules_or_hours`, Nmbr calculates a fixed-hours amount equal to `hours` Γ— the rate of the hourly pay rate selected by `pay_rate`. The pay rate is resolved against the work assignment's hourly pay rates that are effective on the holiday's observed date. If no hourly pay rate is effective on that date, the fixed-hours amount is \$0. For `provincial_rules_or_hours`, Nmbr calculates both the provincial amount and the fixed-hours amount and uses whichever is greater. ## Provincial Rules Calculations Nmbr supports statutory holiday pay calculations for every province and territory. When `calculation_strategy` is `provincial_rules_only` or `provincial_rules_or_hours`, entitlement amounts under provincial rules are calculated as follows: | Province or Territory | Rule | Entitlement Amount Calculation | Included Earning Types | | ------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Alberta | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 20 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Non-Discretionary) | | British Columbia | Regular earnings | The last 30 days of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 21.42 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Non-Discretionary)
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | Manitoba | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 20 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Non-Discretionary)
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | New Brunswick | Regular earnings | The last 30 days of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 21.42 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Non-Discretionary) | | Newfoundland and Labrador | Regular earnings | The last 3 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 15 | - Wage
- Overtime
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Discretionary)
- Bonus (Non-Discretionary)
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | Nova Scotia | Regular earnings | The last 30 days of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 21.42 | - Wage
- Overtime
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Non-Discretionary)
- Statutory Holiday Pay | | Northwest Territories | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 20 | - Wage
- Overtime
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | Nunavut | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 20 | - Wage
- Overtime
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | Ontario | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday week begins (`before_holiday_week`), divided by 20 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Bonus (Non-Discretionary)
- Statutory Holiday Pay | | Prince Edward Island | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 20 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | Quebec | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday week begins (`before_holiday_week`), divided by 20 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Gratuity
- Statutory Holiday Pay | | Quebec | Commission | The last 12 weeks of included earnings, ending the day before the holiday week begins (`before_holiday_week`), divided by 60 | - Commission | | Saskatchewan | Regular earnings | The last 4 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 20 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission
- Vacation Pay
- Vacation Pay (Employee Terminated)
- Vacation Pay (Time Taken)
- Vacation Pay (No Time Taken)
- Statutory Holiday Pay | | Yukon | Regular earnings | The last 2 weeks of included earnings, ending the day before the holiday is observed (`before_holiday_day`), divided by 10 | - Wage
- Retroactive Pay
- Retroactive Pay Increase
- Commission | ## Earned-On Dates Earning, allowance, and reimbursement line items have an optional `earned_on` date that represents the day the line item was earned on. When `earned_on` is set, Nmbr can determine precisely whether a line item falls within a holiday's lookback window. If a line item's `earned_on` date is in the window, the item's amount is included in full; if not, it is excluded entirely. For example, in Ontario the lookback window is the 4 weeks ending the day before the holiday week begins. A bonus with an `earned_on` date inside that window contributes its full amount to the entitlement calculation. The same bonus with an `earned_on` date outside the window contributes nothing. Each line item exposes three earned-on fields: * `managed_earned_on` - The system-assigned earned-on date. * `custom_earned_on` - An override you can set via the API or Portal. Must fall within the payroll's pay period. * `earned_on` β€” The effective value: `custom_earned_on` if set, `managed_earned_on` otherwise. Read-only. ## Proration When a line item has no `earned_on` date, Nmbr falls back to proration. The line item's contribution to the entitlement calculation is scaled by how much of its pay period overlaps with the lookback window. For example, in Ontario the lookback window is the 4 weeks ending the day before the holiday week begins. Depending on the date of the holiday and the pay schedule, that window may cover 0, 1, or 2 partial pay periods. If the window covers 5 days of a 30 day pay period, undated line items from that pay period contribute 5/30ths (1/6th) of their value to the entitlement calculation. Proration is a coarser approximation than `earned_on`-based inclusion: it assumes line items are spread evenly across the pay period, which may over- or under-count earnings that were actually concentrated at one end of the period. Setting `custom_earned_on` on line items where the precise date is known will produce more accurate entitlement amounts. It is also sometimes possible to avoid proration for undated line items by aligning pay periods with the lookback window: * Use a weekly or bi-weekly pay frequency. * Set `override_rule_set` to a province or territory whose entitlement amount calculations are based on an even number of weeks. * Set `override_date_basis` to `before_holiday_pay_period`. This will result in the entitlement amount including earnings only from complete 1- or 2-week pay periods. However, the results may not be correct according to the work assignment's Province of Work's regulations, and the employee may be over- or under-paid what they are actually entitled. ## Statutory Holiday Pay on Statutory Holiday Pay Some provinces and territories include statutory holiday pay for one holiday in the earnings for another holiday. For example, statutory holiday pay earned for Christmas may need to be included when calculating the entitlement amount for Boxing Day, and both may need to be included when calculating the entitlement amount for New Years Day. Nmbr accounts for this both for statutory holidays in earlier pay periods and for statutory holidays in the same pay period. ## Off-Cycle Payrolls An off-cycle payroll covers the same pay period as the regular payroll it was created against, so it observes the same statutory holidays. An employee is entitled to one amount per holiday, however many pay stubs cover the period. Before allocating statutory holiday pay on a draft payroll, Nmbr looks for statutory holiday pay the work assignment has already been allocated for the same holiday on another pay stub covering the same pay period. Pay stubs on approved and paid regular and off-cycle payrolls count. A line item only counts towards a holiday when `is_managed` is `true` and its `earned_on` date matches the holiday's observed date. Statutory holiday pay you add yourself is a payment in its own right, so it doesn't reduce what Nmbr allocates. Then Nmbr allocates the difference: * Nothing has been allocated for the holiday yet, so the entitlement is allocated in full. This is what happens for an employee hired after the regular payroll was approved. * Part of the entitlement has been allocated, so only the remainder is allocated. A retroactive raise on the off-cycle can raise the entitlement above what the regular payroll paid, for example. * The whole entitlement has been allocated, so no line item is created. A line item created by an earlier calculation is removed. Approving a regular payroll recalculates its draft off-cycle payrolls, and so does returning it to draft. The amounts move as soon as the entitlement changes hands. Send a request to the Explain Statutory Holiday Pay endpoint (`POST /calculations/statutory_holiday_pay`) to see how a pay stub's amounts were reached. Each holiday reports `gross_amount` (the full entitlement), `already_allocated` (the amount, hours, and pay stubs it was already allocated on), and `amount` (what this pay stub allocates). ## Limitations **Eligibility:** Each province and territory has its own rules for determining whether employees are eligible for statutory holiday pay. Nmbr does not currently calculate eligibility. If the statutory holiday pay tax property is created on a work assignment, the employee is assumed to be eligible for statutory holiday pay. **Over-allocation:** When the amount already allocated for a holiday is greater than the entitlement, Nmbr allocates nothing rather than a negative amount. Use a `correction` payroll to reduce an amount that has already been paid. **Industry-Specific Rules:** Some provinces and territories have additional industry-specific rules for statutory holiday pay in industries such as construction. Nmbr does not currently apply these rules. # Territorial Payroll Tax Source: https://docs.nmbr.co/guides/canada/territorial-payroll-tax The **Northwest Territories** and **Nunavut** each levy a territorial payroll tax on employee remuneration. The rules for who is subject to this tax and when it applies differ between the two territories. For details, refer to the official territorial government resources: * [Northwest Territories Payroll Tax](https://www.fin.gov.nt.ca/en/services/licences-taxes-et-droits/payroll-tax) * [Nunavut Payroll Tax](https://www.gov.nu.ca/en/taxation-and-insurance/payroll-tax) ## How it works in Nmbr When territorial payroll tax is enabled for a work assignment, Nmbr calculates the tax on all remuneration that is subject to federal income tax. This amount appears as a **Territorial Income Tax** statutory withholding line item on the pay stub. Territorial payroll tax is **not remitted by Nmbr**. The employer is responsible for registering with the territorial government and remitting the tax. The liability report will reflect the territorial payroll tax amounts owed. ## Enabling territorial payroll tax Territorial payroll tax is controlled through [Tax Properties](/guides/payroll-fundamentals/tax-properties) at the **work assignment** level. Each territory has its own tax property type: | Territory | Tax Property Type | | --------------------- | --------------------------------- | | Northwest Territories | `ca::nt::territorial_payroll_tax` | | Nunavut | `ca::nu::territorial_payroll_tax` | To enable territorial payroll tax for an employee, create a tax property on their work assignment with `enabled` set to `true`.
Sample Request ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "effective_from": "2025-01-01", "type": "ca::nt::territorial_payroll_tax", "value": { "enabled": true } }' ```
> Territorial payroll tax is independent of the employee's Province of Employment. An employee with a Province of Employment set to Ontario can still be subject to territorial payroll tax if they have the tax property enabled on their work assignment. ## Disabling territorial payroll tax To stop calculating territorial payroll tax for an employee, set the `effective_to` date on the tax property. The tax will no longer be calculated for payrolls with a pay date after the `effective_to` date. ## Reporting The territorial payroll tax amount is included in the **liability report**, showing the amounts owed to each territorial government. Since Nmbr does not remit this tax, it will appear as a **client deposit responsibility** on the report. # Workers Compensation Board (WCB) Source: https://docs.nmbr.co/guides/canada/workers-comp-guide Set up and calculate WCB premiums In Canada, employers may be required to contribute to a Workers’ Compensation Board (WCB), which funds insurance for employees in case of work-related injuries or illnesses. Premiums are calculated based on the employer’s industry classification and total payroll. The Nmbr API supports WCB premium estimation for every province and territory. To enable WCB calculations, a WCB tax-property **must** be configured per province. ## Supported Regions WCB premiums are supported for all Canadian jurisdictions, including: * Alberta – [WCB Alberta](https://www.wcb.ab.ca/) * British Columbia – [WorkSafeBC](https://www.worksafebc.com/) * Manitoba – [WCB Manitoba](https://www.wcb.mb.ca/) * New Brunswick – [WorkSafeNB](https://www.worksafenb.ca/) * Newfoundland and Labrador – [WorkplaceNL](https://workplacenl.ca/) * Northwest Territories and Nunavut – [WSCC](https://www.wscc.nt.ca/) * Nova Scotia – [WCB Nova Scotia](https://www.wcb.ns.ca/) * Ontario – [WSIB](https://www.wsib.ca/) * Prince Edward Island – [WCB PEI](https://www.wcb.pe.ca/) * Quebec – [CNESST](https://www.cnesst.gouv.qc.ca/) * Saskatchewan – [WCB Saskatchewan](https://www.wcbsask.com/) * Yukon – [Yukon Workers' Compensation Health and Safety Board](https://www.wcb.yk.ca/) ## Enabling WCB Calculation To calculate WCB premiums in any province or territory, you **must** define a WCB tax-property for each work-assignment using the `tax_properties` API. Each region uses the format `ca::::workers_compensation_class` as the `type` value. For example: * Ontario: `ca::on::workers_compensation_class` * Quebec: `ca::qc::workers_compensation_class` * Yukon: `ca::yt::workers_compensation_class` The `value` object for the tax-property must include: * `rate` (number, **required**) – The WCB premium rate to apply (e.g., 1.85). * `code` (string, **required**) – The business’s WCB classification or rate group code. * `industry` (string, **required**) – A plain-text label describing the business activity or industry. * `historical_remuneration` (number, *optional*) – Year-to-date insurable earnings for the work-assignment, used to reduce premiums at the annual provincial maximum. ``` "value": { "rate": 1.85, "code": "83202", "industry": "Technology consulting", "historical_remuneration": 740000 } ``` > WCB will not be calculated for any work-assignment unless a valid tax-property is configured for its province of employment. ## Provincial Maximums Nmbr automatically applies the **maximum assessable earnings** for each province and territory when calculating WCB. These limits cap the amount of earnings subject to WCB premiums per employee, based on their province of employment (as defined in the work assignment). If provided, `historical_remuneration` is used to improve year-to-date calculation and help anticipate when the provincial cap will be reached. Once the cap is reached, WCB premiums will no longer accrue for that work-assignment, in that province or jurisdiction, for the remainder of the year. ### Sample Request To enable WCB calculation for British Columbia: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "effective_from": "2025-01-01", "type" : "ca::bc::workers_compensation_class", "value" : { "rate" : 2.1, "code": "88500", "industry": "Software development", "historical_remuneration": 1250000 } }' ``` ## WCB Calculation Once enabled, WCB is calculated per payroll and per province. WCB is calculated only on remuneration that is considered insurable under WCB rules, based on the province of employment defined in the work-assignment. The following values are used: * **Payroll remuneration** – Total insurable earnings in the payroll, by province. * **Rate** – The WCB rate provided in the tax-property. * **Classification code and industry** – For reference and reporting. * **Provincial maximums** – premiums are capped at the maximum insurable earnings per employee per year, based on province of employment. * **Historical remuneration** – Used to calculate the total to-date remuneration for the work-assignment in the province of employment. When WCB is enabled for a work-assignment, a line item of type `wcb` will be created under `employer_statutory_withholdings` on the pay stub. > Once the annual cap is reached, no further WCB premiums will accrue for that work-assignment in the applicable province for the remainder of the year. ## Remittance In Quebec, CNESST premiums are remitted directly to Revenue Quebec by Nmbr along with other statutory remittances. For other jurisdictions, Nmbr can handle automated remittance for select workers’ compensation providers. ### Enabling Automated Remittance For Nmbr to remit on your behalf, the workers’ compensation [Remittance Account](/api-reference/remittance-accounts/create-a-remittance-account) must exist and its information must be accurate, including `last_payment_amount` in its `metadata`. Set `last_payment_amount` to the amount of the last payment made to the board before Nmbr takes over, whether you made it manually or a previous provider did. Remittance Accounts are sometimes pre-seeded for you. Look for an existing workers’ compensation account before creating one. **Find an existing account** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/remittance_accounts?business_entity_id=&category=ca_workers_compensation' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` If none exists, [create one](/api-reference/remittance-accounts/create-a-remittance-account) with `account_provider` set to your province’s board (for example, `ca_on_workers_compensation` for Ontario’s WSIB). **Set the last payment amount** ```bash theme={null} curl --request PATCH \ --url https://sandbox.nmbr.co/services/payroll/remittance_accounts/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "metadata": { "last_payment_amount": "1250.00" } }' ``` `last_payment_amount` is specific to workers’ compensation accounts and is returned in the account’s `metadata`. ## WCB Reporting Estimated WCB premiums are included in the `workers-compensation` [report](/api-reference/reports/create-wcb-report). # Year-End Tax Forms (T4 / T4A / RL-1) Source: https://docs.nmbr.co/guides/canada/year-end-tax-forms Generate, validate, and submit year-end tax forms to the CRA and Revenu QuΓ©bec Nmbr supports generating, validating, and submitting Canadian year-end tax forms: * **T4 / T4A** β†’ Canada Revenue Agency (CRA) * **RL-1** β†’ Revenu QuΓ©bec For official guidance on form requirements and box definitions, refer to: * [Canada Revenue Agency – T4 Information](https://www.canada.ca/en/revenue-agency/services/tax/businesses/topics/payroll/completing-filing-information-returns/t4-information-employers/t4-slip.html) * [Canada Revenue Agency – T4A Information](https://www.canada.ca/en/revenue-agency/services/tax/businesses/topics/payroll/completing-filing-information-returns/t4a-information-payers/t4a-slip.html) * [Revenu QuΓ©bec – RL-1 Information](https://www.revenuquebec.ca/en/businesses/source-deductions-and-employer-contributions/filing-rl-slips-and-the-rl-1-summary-general-information/) ## Form Lifecycle 1. **draft** – Generated but not yet approved 2. **approved** – Validated and locked for submission 3. **processing** – Submitted to Nmbr for processing 4. **submitted** – Receipt confirmed by the tax authority 5. **done** – Processing completed by the tax authority ## Generating Year-End Tax Forms Year-end tax forms can be generated by payroll administrators in: * the [Nmbr Component](/components/getting-started) * the Nmbr Portal under **Business Entities** * the Nmbr API using the [Generate Forms](/api-reference/form-types/generate-forms) endpoint Generated forms are populated using payroll data for the selected tax year and grouped into a form batch. ### Generating Forms via API Using the [Generate Forms](/api-reference/form-types/generate-forms) endpoint, specify the `form_type` and `tax_year`. You can optionally provide: * `form_batch_id` to group generated forms into an existing batch. * `employee_ids` to generate forms for specific employees only (T4/RL-1). * `contractor_ids` to generate forms for specific contractors only (T4A). * `province_of_employment` to restrict forms to a single province (T4). The response will include an async task which can be tracked using the [Async Task](/api-reference/async-tasks/retrieve-an-async-task) endpoint. Once the task is complete, the generated forms can be retrieved using the [List Forms](/api-reference/forms/list-forms) endpoint. Forms will only be generated for employees/contractors with paid pay stubs in the given tax year. ## Retrieving Year-End Tax Forms Use the [List Forms](/api-reference/forms/list-forms) endpoint with the `type` query parameter set to `t4`, `t4a`, or `rl1`. ## Validation Validate form fields using the [Form Type Validation](/api-reference/form-types/validate-a-form) endpoint. The list of form fields can be retrieved from the [Form Type](/api-reference/form-types/retrieve-a-form-type) endpoint. Forms must have **no validation errors** before they can be approved. ## Approving a Form Forms in `draft` status can be approved once valid using the [Approve Form](/api-reference/forms/approve-a-form) endpoint. Approval locks the form for submission. ## Submitting a Form Batch Year-end forms must be submitted as part of a **form batch**. Use the [Submit Form Batch](/api-reference/form-batches/submit-a-form-batch) endpoint. A batch can only be submitted when all forms in the batch are valid and approved. On submission: * All forms move to `processing` * T4/T4A forms are submitted to the CRA * RL-1 forms are submitted to Revenu QuΓ©bec When the submission is successfully received by the tax authority, forms will move to `submitted` status. When the tax authority completes processing, forms will move to `done` status. The time to complete processing can vary based on the tax authority's workload and processing times. When the form batch is marked `done`, a `form_batch_completed` [webhook](/api/overview/webhook-structure) event will be triggered. If any forms are rejected by the tax authority, the Nmbr team will reach out with details on the errors and next steps to resolve. ## Downloading PDFs ### Individual Form PDF PDF versions of individual forms can be retrieved using the [Retrieve Form](/api-reference/forms/retrieve-a-form) endpoint with the `Accept: application/pdf` header. PDFs are only available for forms with no validation errors. PDFs for valid forms that are not yet `done` will be watermarked with "DRAFT" to indicate they are not yet complete. ### Batch PDF A zip file containing all forms in a batch can be downloaded once all forms are marked `done` using the [Download Form Batch](/api-reference/form-batches/download-a-form-batch) endpoint. ## Email There are two emails associated with year-end tax forms: 1. **Form Batch Completion Email** – Sent to the form batch contact when the batch is marked `done`. 2. **Form Recipient Email** – Sent to employees/contractors. Can be triggered in the Nmbr Component by the payroll administrator, or in the Partner Portal. See [Configuring Email](/portal/configuring-email) for more details. ## Amending Forms Once a form batch is submitted, forms cannot be edited. If changes are needed, an official amendment must be made with the tax authority. Amendments can only be performed on forms in `done` status. Amendments can be performed: * in the [Nmbr Component](/components/getting-started) * in the Nmbr Portal on the form details page * via the Nmbr API using the [Amend a Form](/api-reference/forms/amend-a-form) endpoint Amending a form will create a new amendment form linked to the original form (as `source_form_id`). The amendment form will have its own lifecycle and must be approved and submitted to the tax authority. ## Deadlines The deadline for submitting year-end tax forms to the CRA and Revenu QuΓ©bec is typically the **last day of February** following the tax year. For example, for the 2025 tax year, forms must be submitted by March 2, 2026 (since February 28 falls on a Saturday, the deadline moves to the next business day). Late or missed filings may result in penalties from the CRA or Revenu QuΓ©bec. It is the responsibility of the payroll administrator to ensure forms are generated, approved, and submitted by the deadline. Nmbr recommends starting the process early to allow time for resolving any validation errors or issues with the tax authority. # Overview Source: https://docs.nmbr.co/guides/getting-started/overview Welcome to the Nmbr API documentation! Nmbr enables software providers with a feature-rich API platform for building financial products. We handle the complexities of tax calculation, payments, and regulatory compliance so that you can focus on delivering a unique financial experience for your customers. To get started take a look at our [Quickstart guide](/guides/getting-started/quickstart). Specific API documentation is available in our [API Reference](/api/overview/authentication). ## Recommended Guides * [Quickstart Guide](/guides/getting-started/quickstart): A step-by-step guide to getting started with the Nmbr API. This guide will demonstrate how to create companies, employees, and payrolls β€” the actions required to get employees paid accurately and reliably. ## API Deep Dives * [Payroll](/guides/payroll-fundamentals/payroll-lifecycle): This documentation guides you through the steps required to create, modify, and approve a payroll. You will also learn more about the lifecycle of payroll. * [Benefits](/guides/payroll-fundamentals/configuring-benefits): Learn about Nmbr's approach to handling recurring employee benefits, ensuring premiums are correctly calculated, and company contributions are accounted for. * [Company Setup & KYB](/guides/payroll-fundamentals/company-setup): Learn how to create a company, create a business entity, and send the customer through business verification. > πŸ“˜ Ready to get started? > Request your API key to begin exploring the Nmbr API for yourself. If you have any questions please schedule a discovery session to see a live demo and learn more about working with Nmbr. # Quickstart Source: https://docs.nmbr.co/guides/getting-started/quickstart Securely and reliably integrate payroll into your product. This guide will demonstrate the required interactions with the Nmbr API in order for employees to get paid reliably and on time. # Company Configuration ## Create a company The first action is to create a company, the overarching container that represents a single customer. **Authentication Note** You will use your `partner_secret` to create the top-level company. Once a company is created, future API calls should use the returned `access_token` to ensure interactions are always scoped to an individual company account. Company-level `access_tokens` are short-lived and will need to be refreshed before they expire. Read more about [Authentication](/api/overview/authentication) in API Reference. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/companies \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "name": "Bouchard Burger Inc." }' ``` **Response** ```json theme={null} { "id": "01hhcy3fc40cp6yyv500re1041", "object": "company", "data": { "name": "Bouchard Burger Inc.", "pay_day_movement_setting": "inherit", "created_at": "2023-12-11T17:16:55.000000Z", "updated_at": "2023-12-11T17:16:55.000000Z", "token": { "access_token": "4nWkuMVylVeJMkOiFaPMzbQwdUklsP08sIqkBifve92a05c2", "expires_in": 59, "expires_at": "2023-12-11T18:16:55.000000Z" } }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hhcy3fc40cp6yyv500re1041" } } ``` You should store both the returned company ID as well as the token object for future interactions with the Nmbr API. ```json theme={null} "token": { "access_token": "4nWkuMVylVeJMkOiFaPMzbQwdUklsP08sIqkBifve92a05c2", "expires_in": 59, "expires_at": "2023-12-11T18:16:55.000000Z" } ``` ## Create a business entity The next action is to create a business entity, the employer that is paying employees. Each business entity is a separate tax entity to tax agencies and has one Canadian payroll account and business number (BN). Use the customer scoped `access_token` for all requests related to this customer going forward. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/business_entities \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "business_number": "36774676RP0001", "name": "Bobs Burgers (#67667)", "legal_name": "8877362 Inc" }' ``` **Response** ```json theme={null} { "id": "01hhcy3fpqkez7wjqzeaqetwfs", "object": "business_entity", "data": { "business_number": "36774676RP0001", "name": "Bobs Burgers (#67667)", "legal_name": "8877362 Inc", "address_line_1": "13 Fake Street", "address_line_2": null, "city": "Toronto", "province_code": "ON", "country_code": "CA", "postal_code": "M1M1M1", "contact_name": "kevin", "contact_area_code": "905", "contact_phone_number": "1112233", "contact_extension": null, "pay_day_movement_setting": "inherit", "onboarding_status": "incomplete", "created_at": "2023-12-11T17:16:55.000000Z", "updated_at": "2023-12-11T17:16:55.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/01hhcy3fpqkez7wjqzeaqetwfs" } } ``` You should store at least the returned business entity ID for future interactions with the Nmbr API. Read more about [Company Setup](/guides/payroll-fundamentals/company-setup) in Payroll Fundamentals. ## Create a pay schedule A payroll schedule determines the length of your pay period and how often you pay your employees. The most common payroll schedules are weekly, biweekly, semimonthly, and monthly. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_schedules \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "title": "Salary Schedule", "pay_frequency": "semi-monthly", "anchor_pay_date": "2023-01-15T00:00:00.000000Z", "anchor_end_of_pay_period": "2023-01-15T00:00:00.000000Z", "day_1": 15, "day_2": -1, "business_entity_id": "{business_entity_id}" }' ``` **Response** ```json theme={null} { "id": "01hhcy3ftxe4wrcsyzf7a3a46q", "object": "pay_schedule", "data": { "title": "Salary Schedule", "pay_frequency": "semi-monthly", "anchor_pay_date": "2023-01-15T00:00:00.000000Z", "anchor_end_of_pay_period": "2023-01-15T00:00:00.000000Z", "day_1": 15, "day_2": -1, "pay_day_movement_setting": "inherit", "created_at": "2023-12-11T17:16:56.000000Z", "updated_at": "2023-12-11T17:16:56.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_schedules/01hhcy3ftxe4wrcsyzf7a3a46q" } } ``` You should store at least the returned pay schedule ID for future interactions with the Nmbr API. Read more about [Managing Pay Schedules](/guides/payroll-fundamentals/managing-pay-schedules) in Payroll Fundamentals. # Employee Configuration ## Create an employee Creating an employee is very similar to creating a business entity. You will make an API request to create an employee entity in the payroll system. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/employees \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "employee_number": "69878", "first_name": "Kendall", "last_name": "Hintz", "middle_initial": null, "address_line_1": "Spencer Meadows", "address_line_2": null, "city": "Toronto", "province_code": "on", "country_code": "CA", "postal_code": "M1M1M1", "sin": "" }' ``` **Response** ```json theme={null} { "id": "01hhcy3hg60x3dq8hfj31hgyea", "object": "employee", "data": { "employee_number": "69878", "first_name": "Kendall", "last_name": "Hintz", "middle_initial": null, "address_line_1": "Spencer Meadows", "address_line_2": null, "city": "Toronto", "province_code": "ON", "country_code": "CA", "postal_code": "M1M1M1", "sin": "", "archived_at": null, "created_at": "2023-12-11T17:16:57.000000Z", "updated_at": "2023-12-11T17:16:57.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/employees/01hhcy3hg60x3dq8hfj31hgyea" } } ``` You should store at least the returned employee ID for future interactions with the Nmbr API. Read more about [Adding Employees](/guides/payroll-fundamentals/adding-employees) in Payroll Fundamentals. ## Create Work Assignment You will be required to tie an employee and pay schedules together to ensure accurate payroll statutory withholdings. A Work Assignment can be created by providing the appropriate IDs to the Work Assignments endpoint. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/work_assignments \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "employee_id": "{employee_id}", "pay_schedule_id": "{pay_schedule_id}" }' ``` **Response** ```json theme={null} { "id": "01hhcy3hmeajydc6cpa1k5s5kr", "object": "work_assignment", "data": { "created_at": "2023-12-11T17:16:58.000000Z", "updated_at": "2023-12-11T17:16:58.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/work_assignments/01hhcy3hmeajydc6cpa1k5s5kr" } } ``` Creating a work assignment linked to a pay schedule will generate the upcoming pay stubs for each pay period in the system. Read more about [Work Assignments](/guides/payroll-fundamentals/adding-employees#work-assignments) in Payroll Fundamentals. ## Setup pay rates Paying out earnings to employees is one of the primary functions of payroll software. Depending on the province or territory of employment, different labour laws apply relating to minimum wage and vacation earnings. You can create a Pay Rate for an employee using the pay\_rate endpoint: **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_rates \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "{work_assignment_id}", "title": "Location Manager", "type": "salary", "rate": "60000", "expected_hours_per_week": "38", "effective_from": "2023-11-01T00:00:00.000000Z" }' ``` **Response** ```json theme={null} { "id": "01hhcy3j61408834dmfe8bzg24", "object": "pay_rate", "data": { "title": "Location Manager", "type": "salary", "rate": 60000, "expected_hours_per_week": 38, "effective_from": "2023-11-01T00:00:00.000000Z", "effective_to": null, "created_at": "2023-12-11T17:16:58.000000Z", "updated_at": "2023-12-11T17:16:58.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_rates/01hhcy3j61408834dmfe8bzg24" } } ``` Read more about [Setup Pay Rates](/guides/payroll-fundamentals/setup-pay-rates) in Payroll Fundamentals. # Payroll Configuration ## Retrieve payroll information When a payroll is first created, it will be in the draft status. You can retrieve draft payrolls and display totals for the end user. First, retrieve a list of all payrolls, then retrieve the individual payroll that you would like to review, change, or approve. **Request** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/payrolls?business_entity_id={business_entity_id}' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/payrolls/{payroll_id} \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "id": "01hfvzcp9c5phwfjkcra40rsg4", "object": "payroll", "data": { "type": "regular", "period_start": "2023-01-01T00:00:00.000000Z", "period_end": "2023-01-15T00:00:00.000000Z", "pay_date": "2023-01-13T00:00:00.000000Z", "employee_summary": { "gross": 1161.54, "subtractions": 449.23, "reimbursements": 0, "net": 712.31 }, "contractor_summary": { "gross": 100, "reimbursements": 15, "net": 115 }, "company_summary": { "taxes_and_contributions": 73.56, "benefits": 50, "total": 123.56 }, "liability": 1150.1, "cash_requirement": 1150.1, "status": "draft", "approved_at": null, "created_at": "2023-11-22T16:56:38.000000Z", "updated_at": "2023-11-22T16:56:38.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/payrolls/01hfvzcp9c5phwfjkcra40rsg4" } } ``` Read more about [Payroll Lifecycle](/guides/payroll-fundamentals/payroll-lifecycle) in Payroll Fundamentals. ## Retrieve an employee's earnings & deductions In order to make adjustments to individual employee's earnings and deductions, you will need to retrieve the corresponding pay stub. Payments to employees can be added and removed, earnings and hours worked can be modified on individual payroll items, etc. You can retrieve a payroll and include all corresponding pay stubs using the ?expands=\[] functionality. Read more about [working with related resources](/api/overview/response-structure) in the API Reference. **Request** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/payrolls/{payroll_id}?expand[]=pay_stubs' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/pay_stubs/{pay_stub_id}' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "id": "01hfwg2784vc1408yhmjp4x81q", "object": "pay_stub", "data": { "payroll": { "id": "01hfvzcp9c5phwfjkcra40rsg4", "object": "payroll", "links": { "self": "https://sandbox.nmbr.co/services/payroll/payrolls/01hfvzcp9c5phwfjkcra40rsg4" } }, "work_assignment": { "id": "01hfwg1t8v9m2c3q7pk4d5znab", "object": "work_assignment", "links": { "self": "https://sandbox.nmbr.co/services/payroll/work_assignments/01hfwg1t8v9m2c3q7pk4d5znab" } }, "payment_method": "direct_deposit", "has_taxes_calculated": true, "is_pending_tax_rates": false, "employee_summary": { "gross": 2520, "subtractions": 714.91, "reimbursements": 10, "net": 1815.09, "gross_ytd": 2520, "subtractions_ytd": 714.91, "reimbursements_ytd": 10, "net_ytd": 1815.09 }, "contractor_summary": { "gross": null, "reimbursements": null, "net": null, "gross_ytd": 0, "reimbursements_ytd": 0, "net_ytd": 0 }, "company_summary": { "taxes_and_contributions": 500, "benefits": 50, "total": 550, "taxes_and_contributions_ytd": 500, "benefits_ytd": 50, "total_ytd": 550 }, "vacation_pay_balance": 0, "liability": 3080, "cash_requirement": 3080, "note": null, "line_item_summary": { "earnings": { "period": 2520, "period_managed": 2520, "period_unmanaged": 0, "ytd": 2520 }, "statutory_withholdings": { "period": 634.91, "ytd": 634.91 }, "reimbursements": { "period": 10, "ytd": 10 }, "allowances": { "period": 0, "ytd": 0 }, "employee_benefits": { "period": 30, "ytd": 30 }, "employer_benefits": { "period": 50, "ytd": 50 }, "deductions": { "period": 50, "ytd": 50 } }, "is_stale": false, "stale_since": null, "warnings": { "object": "list", "data": [] }, "external_ref": null, "apply_standard_tax_reductions": false, "created_at": "2023-11-22T21:48:01.000000Z", "updated_at": "2023-11-23T15:51:21.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/01hfwg2784vc1408yhmjp4x81q" } } ``` You can update an individual payroll line item using the API. The example below could be used to enter 10 hours for the given pay rate. **Request** ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/earnings/{earning_id} \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "hours": 10 }' ``` Read more about [Additional Line Items](/guides/payroll-fundamentals/additional-line-items) in Payroll Fundamentals. You will notice changes to earnings automatically update related statutory withholdings and tax calculations. You can leverage webhooks to show payroll calculation changes to your users. Read more about [Webhooks](/api/overview/webhook-structure) in the API Reference. ## Approve payroll When a payroll is approved (via the `/payrolls//` approve endpoint), its status changes to approved. Once approved, the payroll can no longer be modified. This is because the taxes, net pay, and benefits have been calculated and saved for the payroll. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls/{payroll_id}/approve \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` At the end of each business day at 5pm PT, our system collects all pending payrolls that have an approval deadline on that day and begins the multi-step process of moving money through the banking system to pay them out. Read more about the [Payroll Life Cycle](/guides/payroll-fundamentals/payroll-lifecycle) in Payroll Fundamentals. ## Generate pay stubs Nmbr also provides the ability to generate pay stubs for employees both as a rendered PDF and as a JSON object. Because CRA regulations generally require that all information in the pay stub JSON response be rendered and the pay stub be printable, Nmbr recommends directly rendering a singular pay stub to PDF to satisfy this requirement. To return a pay stub as a JSON response, make a GET call to the /pay\_stubs endpoint: ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/pay_stubs/{pay_stub_id} \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` To return a pay stub as a PDF response, make a GET call to the `/pay_stubs/{pay_stub_id}/render` endpoint: ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/pay_stubs/{pay_stub_id}/render \ --header 'Authorization: Bearer ' \ --header 'accept: application/pdf' ``` Draft pay stub PDFs will be rendered with a "DRAFT" watermark. ## What's Next As a next step we suggest browsing our [API Reference](/api/overview/authentication). # Adding Employees Source: https://docs.nmbr.co/guides/payroll-fundamentals/adding-employees Manually capturing employee onboarding requirements ## Capture employee information Creating an employee in Nmbr requires providing the required information to the employee API endpoint. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/employees \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "employee_number": "69878", "first_name": "Kendall", "last_name": "Hintz", "middle_initial": null, "address_line_1": "Spencer Meadows", "address_line_2": null, "city": "Toronto", "province_code": "ON", "country_code": "CA", "postal_code": "M1M1M1", "sin": "" }' ``` **Response** ```json theme={null} { "id": "01hhcy3hg60x3dq8hfj31hgyea", "object": "employee", "data": { "employee_number": "69878", "first_name": "Kendall", "last_name": "Hintz", "middle_initial": null, "address_line_1": "Spencer Meadows", "address_line_2": null, "city": "Toronto", "province_code": "ON", "country_code": "CA", "postal_code": "M1M1M1", "sin": "", "archived_at": null, "created_at": "2023-12-11T17:16:57.000000Z", "updated_at": "2023-12-11T17:16:57.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/employees/01hhcy3hg60x3dq8hfj31hgyea" } } ``` ## Work Assignments A core concept in the Nmbr API is Work Assignments. Work Assignments allow you to attach an Employee and Pay-Rates to a Pay Schedule. Work Assignments offer a flexible data architecture to allow you to represent both simple and complex employment scenarios depending on your requirements. An Employee may have multiple Work Assignments, which can represent different jobs or work held by the employee within a single Business Entity. This may depend on your product needs and data architecture. When creating a Benefit, Deduction, Reimbursement, or Allowance, these entities are attached to a Work Assignment. This allows Nmbr to know which Pay-Schedule to apply these on. ### How Business Entity influences Work Assignments * An Employee may have multiple Work Assignments within a single Company. * An Employee may only have one Work Assignment per Pay-Schedule. * A single Work Assignment may have multiple Pay-Rates. * CPP and EI Statutory Withholding limits are calculated across all Work Assignments for an Employee within a single Business Entity - meaning Employee and Employer contributions should not exceed their maximum contribution limits. * A Work Assignment inherits the Business Entity's Province of Employment by default. If the Work Assignment should use a different province, create a `ca::province_of_employment` Tax Property for the Work Assignment. You can include this in `tax_properties` when creating the Work Assignment or create it later using the [Province of Employment guide](/guides/payroll-fundamentals/province-of-employment). ### Creating a Work Assignment ```bash theme={null} curl --request POST \ --url 'https://sandbox.nmbr.co/services/payroll/work_assignments' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "employee_id": "", "pay_schedule_id": "", "tax_properties": [ { "type": "ca::province_of_employment", "value": "ca_on", "effective_from": "2026-01-01" } ] }' ```
View sample JSON Response ```json theme={null} { "id": "01j29zj9tng0db7qhs9et8f8z7", "object": "work_assignment", "data": { "title": null, "employee": { "id": "01j18hrp4cvvbzr1y9x8m05tdf", "object": "employee", "links": { "self": "https://sandbox.nmbr.co/services/payroll/employees/01j18hrp4cvvbzr1y9x8m05tdf" } }, "pay_schedule": { "id": "01j18hrnkac0btavbxhk8g56kx", "object": "pay_schedule", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_schedules/01j18hrnkac0btavbxhk8g56kx" } }, "business_entity": { "id": "01j18hrng6h90bxgfz92re28ab", "object": "business_entity", "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/01j18hrng6h90bxgfz92re28ab" } }, "current_tax_jurisdiction": "ca_on", "accrued_vacation_pay": 0, "paid_vacation_pay": 0, "archived_at": null, "created_at": "2024-07-08T20:11:37.000000Z", "updated_at": "2024-07-08T20:11:37.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/work_assignments/01j29zj9tng0db7qhs9et8f8z7" } } ```
### Removing a Work Assignment * Work Assignments may only be deleted when there are no Pay Stubs with a status of `processing`, `failed`, or `paid`. * A Work Assignment may be archived to remove it from future Payrolls. Archived Work Assignments are also removed by default from lists of Work Assignments. # Additional Line Items Source: https://docs.nmbr.co/guides/payroll-fundamentals/additional-line-items ## What is an allowance, a reimbursement, or a garnishment ### Allowance An allowance or an advance is any periodic or lump-sum amount that you pay to your employee on top of salary or wages, to help the employee pay for certain anticipated expenses without having them support the expenses. An allowance or advance is: * usually an arbitrary amount that is predetermined without using the actual cost * usually for a specific purpose * used as the employee chooses, since the employee does not provide receipts An allowance can be calculated based on distance, time or something else, such as a motor vehicle allowance using the distance driven or a meal allowance using the type and number of meals per day. Nmbr supports the ability to configure one-time and recurring allowances. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/allowances \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "01h7e1ayty45hwns4k781sv80e", "allowance_type": "automobile_and_motor_vehicle", "amount": 10, "frequency": "per_month", "effective_from": "2023-01-01", "effective_to": null }' ``` ### Reimbursement A reimbursement is an amount you pay to your employee to repay expenses they incurred while carrying out the duties of employment. The employee must keep proper records (detailed receipts) to support the expenses and give them to you. Nmbr supports the ability to configure one-time and recurring reimbursements. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/reimbursements \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "01h7e1ayty45hwns4k781sv80e", "reimbursement_type": "non_taxable_reimbursement", "amount": 10, "frequency": "per_month", "effective_from": "2023-01-01", "effective_to": null }' ``` ### Deductions A deduction is an amount you deduct from your employee's earnings and remit to another recipient such as the CRA. For example, if your employee owes the CRA a sum of money and refuses to pay it, it is possible that the CRA may garnish that employee's wages. In such a case, the CRA will send you a request - such as a Requirement to Pay (RTP) notice - for you to send the amount owed to the CRA instead of giving it to the employee. You are responsible for deducting the amount specified in the notice and remitting it to the CRA. If you do not comply with the requirements, you may be held responsible for the amounts you didn't remit. Nmbr supports the ability to configure one-time and recurring deductions. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/deductions \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "01h7e1ayty45hwns4k781sv80e", "deduction_type": "garnishment_order", "amount": 10, "amount_type": "percent", "frequency": "per_payroll", "effective_from": "2023-01-01", "effective_to": null }' ``` ## Updating, ending, and deleting Allowance, reimbursement, and deduction records can be updated, ended, or deleted after a payroll that uses them has been approved. Unlike Tax Properties and Remittance Accounts, these records do not expose `is_editable` or `is_deletable` fields, so you do not need to hide those actions because an approved payroll already used the record. Changes are forward-looking. Draft and future pay stubs use the latest record state the next time they are calculated. Approved payrolls keep the line items and amounts that were approved. * **Update a field** such as `amount`, and draft or future pay stubs use the new value when recalculated. Approved pay stubs keep their original amount. * **End the recurrence** by setting `effective_to`. The line item no longer appears on pay stubs after `effective_to`. Approved pay stubs on or before that date are unchanged. * **Delete the record**, and it is removed from draft and future pay stubs. Approved pay stubs keep the line item that was already approved. This is different from `component_settings.attributes_locked` on pay stub line item resources. That field controls whether the generated line item can be edited in the Nmbr Component; it does not make the source allowance, reimbursement, or deduction record read-only. # Banking Source: https://docs.nmbr.co/guides/payroll-fundamentals/banking Configure bank accounts and payment settings for payroll execution. To execute payroll, Nmbr requires properly configured bank accounts for both employers and employees. This guide outlines how to create bank accounts, manage pre-authorized debit (PAD) agreements, designate primary payment accounts, and handle special cases like manual payment or pay splits. ## Business Banking Configuration ### Create a business bank account Each business entity needs a bank account so Nmbr can withdraw funds and disburse payroll. You can add multiple bank accounts to a business entity, but one must be marked as **primary**. Only the primary account is used for payroll debits. Bank accounts use Canadian banking details. Send these fields when you create one: * `account_number`: the account number. 1 to 12 digits. * `transit_number`: the branch (transit) number. Exactly 5 digits. * `institution_number`: the bank's institution number. Exactly 3 digits. * `is_primary` (optional): mark this account as the primary one. See [Primary Bank Accounts](#primary-bank-accounts). Send each number as a string of digits only, with no spaces or dashes. Keep any leading zeros. Institution numbers like `001` are common. **Request** ```bash theme={null} curl -X POST https://sandbox.nmbr.co/services/payroll/bank_accounts \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "business_entity_id": "", "account_number": "1234567", "transit_number": "12345", "institution_number": "001", "is_primary": true }' ``` See [Creating a bank account](/api-reference/bank-accounts/create-a-bank-account) for the full field list. ### Pre-Authorized Debit (PAD) agreements Before Nmbr can debit a business entity's account, that account needs a signed Pre-Authorized Debit (PAD) agreement. PAD status lives on the bank account, not the business entity. Each business bank account has an `is_pad_signed` field that is either true or false. `is_pad_signed` becomes true once the account has all four of these set: * `pad_signed_at`: the date the agreement was signed. * `pad_signer_name`: the signer's full name. * `pad_signer_email`: the signer's email. * `pad_signer_title`: the signer's job title. Set these fields when you create or update the business bank account, [via the Nmbr API](/api-reference/bank-accounts/update-a-bank-account) or in the Nmbr Portal. Nmbr blocks payroll approval until at least one of the business entity's bank accounts has `is_pad_signed` set to true. There is no separate business-entity-level PAD status. Read `is_pad_signed` on each account to know where things stand. ## Employee and Contractor Bank Accounts ### Create employee or contractor bank accounts Nmbr supports direct deposit to employees and contractors through linked bank accounts. Each employee or contractor can have **multiple** bank accounts configured, but only one can be marked as **primary**. Use the same `account_number`, `transit_number`, and `institution_number` fields as a business account, plus the optional `is_primary`. Send `employee_id` or `contractor_id` instead of `business_entity_id`. PAD fields apply only to business bank accounts. See [Creating a bank account](/api-reference/bank-accounts/create-a-bank-account). ### Missing bank accounts block payroll If an employee or contractor does not have at least one valid bank account, their payroll will be blocked and must be resolved before proceeding. In such cases, you may either: * Add a bank account, or * Update their pay stub's `payment_method` to **manual**. See [Updating a pay stub](/api-reference/pay-stubs/update-a-pay-stub). ## Primary Bank Accounts Only one bank account per business entity, employee, or contractor can be designated as **primary**. This primary account is the one Nmbr will use for financial transactions. To mark an account as primary, include `"is_primary": true` in the request payload when creating or updating a bank account. ## Pay Splits Nmbr allows employees to split their pay across up to **7** bank accounts using either: * **Percentage-based splits** (e.g. 50% to Account A, 50% to Account B), or * **Fixed amount splits** (e.g. \$500 to Account A, remainder to Account B) > πŸ’‘ Note\ > A minimum of two accounts is required to use pay splits. See [Creating a pay split](/api-reference/pay-splits/create-a-pay-split). ### Percentage splits All split percentages must add up to exactly **100%**. Every account used in a percentage split must be explicitly assigned a percentage. ### Fixed amount splits Each account is assigned a fixed dollar amount, except the final account which receives the remainder of the pay. * Do not specify an amount for the last account. It will receive what's left after other accounts are paid. * If the specified amount for an account exceeds the available net pay, Nmbr will skip that account and proceed with the remaining allocations. ### Using Pay Splits Pay splits must be assigned to work assignments. All payments for that work assignment will then follow the defined split. See [Updating a pay split](/api-reference/pay-splits/update-a-pay-split). If instead a pay split should be used for all of an employee's work assignments, the pay split can be set as `default`. The pay split will then be used for all payments unless a specific assignment has its own split defined. See [Creating a pay split](/api-reference/pay-splits/create-a-pay-split). # Company Setup & KYB Source: https://docs.nmbr.co/guides/payroll-fundamentals/company-setup Guide to enrolling a company in Nmbr's payroll services Before Nmbr can process payroll for a company, Nmbr needs information about the company to meet regulatory obligations, determine processing periods, and surface onboarding flows. As a partner, you submit this information through the Nmbr API before the customer's first payroll. This guide walks through the API calls to create the company, create at least one business entity, and send the customer through business verification (KYB). ## 1. Create a company A `Company` is the top-level container for one customer. Create it with your partner secret. The response includes a company-scoped `access_token` for future API calls for that customer. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/companies \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "name": "Bouchard Burger Inc." }' ``` **Response** ```json theme={null} { "id": "01hhcy3fc40cp6yyv500re1041", "object": "company", "data": { "name": "Bouchard Burger Inc.", "pay_day_movement_setting": "inherit", "created_at": "2023-12-11T17:16:55.000000Z", "updated_at": "2023-12-11T17:16:55.000000Z", "token": { "access_token": "4nWkuMVylVeJMkOiFaPMzbQwdUklsP08sIqkBifve92a05c2", "expires_in": 59, "expires_at": "2023-12-11T18:16:55.000000Z" } }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/companies/01hhcy3fc40cp6yyv500re1041" } } ``` ## 2. Create a business entity A business entity is the legal employer that runs payroll. Tax agency accounts, such as CRA payroll accounts, are configured separately as remittance accounts. Required information includes: * Business number * Legal business name * Legal registration number * Address on file * Primary business contact A company can have more than one business entity. Use the company-scoped `access_token` returned when you created the company. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/business_entities \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "business_number": "36774676RP0001", "name": "Bobs Burgers (#67667)", "legal_name": "8877362 Inc", "legal_registration_number": "047738-9", "address_line_1": "13 Main Street", "address_line_2": null, "city": "Toronto", "province_code": "ON", "country_code": "CA", "postal_code": "M1M1M1", "contact_name": "Bob", "contact_area_code": "416", "contact_phone_number": "3748686", "contact_extension": null }' ``` **Response** ```json theme={null} { "id": "01hhcy3fpqkez7wjqzeaqetwfs", "object": "business_entity", "data": { "business_number": "36774676RP0001", "name": "Bobs Burgers (#67667)", "legal_name": "8877362 Inc", "legal_registration_number": "047738-9", "address_line_1": "13 Main Street", "address_line_2": null, "city": "Toronto", "province_code": "ON", "country_code": "CA", "postal_code": "M1M1M1", "contact_name": "Bob", "contact_area_code": "416", "contact_phone_number": "3748686", "contact_extension": null, "status": "onboarding", "in_preview": false, "created_at": "2023-12-11T17:16:55.000000Z", "updated_at": "2023-12-11T17:16:55.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/01hhcy3fpqkez7wjqzeaqetwfs" } } ``` Outcome: Nmbr creates the business entity and starts business verification automatically. You do not need to create a separate verification record. ## 3. Send the customer to business verification KYB stands for "Know Your Business." It is the due diligence process financial companies use to verify a business's identity and assess risk. Nmbr checks the business against corporate registries, sanctions and watchlists, and other AML sources. Nmbr creates a business entity verification when the business entity is created. When verification needs information directly from the business, Nmbr stores a hosted verification link on the business entity verification record. Retrieve the verification record after you create the business entity. Send the customer to the returned `link` so they can complete verification. **Request** ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/business_entities//verification \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "id": "01hj1djve5zcjv1mrbvp3ps6aq", "object": "business_entity_verification", "data": { "status": "requested", "link_status": "not_started", "link": "https://verify.nmbr.co/kyb?token=", "external_id": "vs_abc123", "business_entity": { "id": "01hhcy3fpqkez7wjqzeaqetwfs", "object": "business_entity", "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/01hhcy3fpqkez7wjqzeaqetwfs" } }, "created_at": "2023-12-11T17:16:56.000000Z", "updated_at": "2023-12-11T17:16:56.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/01hhcy3fpqkez7wjqzeaqetwfs/verification" } } ``` Outcome: the customer completes verification from the hosted link. Nmbr receives the result from the verification provider and updates the verification status. Note: the verification link is provider-hosted and may expire. If a link no longer works, contact Nmbr support for a refreshed link. ## 4. Check verification status Use `GET /business_entities//verification` to check the current status. | Status | What it means | What to do next | | ------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `incomplete` | Nmbr created the verification record, but the hosted verification link has not been requested yet. | Try the request again shortly. If the status does not move to `requested`, contact Nmbr support. | | `requested` | The hosted verification link is available and the business is waiting on verification. | Send the customer to the `link`, or wait for the provider result if they already completed it. | | `approved` | The business passed verification. | Continue onboarding. Related business verification warnings are resolved. | | `failed` | The business did not pass verification. | Contact Nmbr support for next steps. The API does not return a machine-readable failure reason. | The `status` field is the verification decision. The `link_status` field only tracks how far the business has gotten through the hosted link: * `not_started`: the link has been shared, but the business has not completed it. * `in_progress`: the business submitted their information and it is being processed. * `complete`: the information is in and has been picked up for review. `link_status` never carries the decision. Read the outcome from `status`. ## Check whether you can approve a payroll Before you call `POST /payrolls//approve`, retrieve the business entity with `GET /business_entities/` and read its `status` field. `status` is the business entity's lifecycle state: `onboarding`, `approved`, or `suspended`. You can approve a payroll once the business entity's `status` is `approved`. The verification endpoint also returns a `status`, but it is the KYB decision: `incomplete`, `requested`, `approved`, or `failed`. Do not use it to determine whether a payroll can be approved. For example, verification can be `approved` while the business entity remains `onboarding`. This check only determines business entity eligibility. The payroll must still meet the endpoint's other approval requirements, such as being draft and fully calculated. Preview Mode is a separate case. A business entity in [Preview Mode](/guides/advanced/preview-mode) (`in_preview` is `true`) can approve payrolls regardless of its `status`, because preview runs never move real money. It is a testing state, not an approval status. ## Business verification warnings Business verification can block onboarding while the status is `incomplete`, `requested`, or `failed`. When the status is `approved`, Nmbr clears the business verification warning. You can then continue with the rest of the company setup flow. ## If verification needs review Automated KYB can fail when business information cannot be validated against registry data, sanctions lists, or other AML checks. If that happens, Nmbr may ask the customer for an identification document so Nmbr can complete manual KYC/KYB review. Nmbr accepts any of the following documents for a business: * Certificate of incorporation/registration * Memorandum/articles of incorporation/association/registration * Directors registry * Shareholder registry * Trust agreement * Proof of address. For example, a utility bill, rent contract, or electricity bill. * Certificate of incumbency * Statement of information * Certificate of good standing Manual review can often take 24 hours after Nmbr has the required information. Partners should not build a separate document-upload step for this guide. Nmbr does not expose an API for partners to upload these documents for business verification. The verification response also does not include a machine-readable failure reason or manual review payload. # Configuring Benefits Source: https://docs.nmbr.co/guides/payroll-fundamentals/configuring-benefits Managing payroll contributions for employee and employer benefits Benefits represent payroll contributions tied to employer or employee plans. These contributions may be monetary or calculated based on earnings, and may be shared between the employer and the employee. Benefits are configured using two distinct entities: * **Employer Benefits**: Contributions paid by the employer towards employee benefit plans. * **Employee Benefits**: Contributions deducted from the employees earnings to contribute to their benefits. Both types can generate **line items** during payroll, which represent actual contributions applied per pay period. *** ## Employer Contributions ### Employer Benefits Employer Benefits represent the configuration of recurring contributions made by the employer towards benefit plans, such as health insurance or retirement contributions. * Employer Benefits are contributions made by the employer towards employee benefit plans. * They can be fixed amounts or calculated based on employee earnings. * During the effective dates, these contributions are automatically applied to the payroll as an Employer Benefit Line Item. * Employer Benefits can be inherited from a Business Preset, allowing for consistent benefit configurations across multiple work assignments. | Field | Description | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `work_assignment_id` | Required. The work assignment this benefit applies to. Must belong to a work assignment associated with an entity of type Employee. | | `business_preset_id` | Optional Business Preset to inherit from. | | `employer_benefit_type` | The type of benefit (e.g. `health`, `pension_rrsp`, `group_term_life_insurance`). Required unless inherited from a Business Preset. | | `employee_benefit_id` | Optional reference to an employee\_benefit used solely for display. | | `title` | Label for identifying the benefit. | | `effective_from` | Start date of the Benefit. | | `effective_to` | The end date for this plan (optional) | | `frequency` | How often the benefit applies (e.g. `once`, `per_payroll`, `per_month`) | | `income_basis` | Income basis used for percentage-based benefits (`regular_earnings`, `total_income`) | | `income_includes` | Narrows which earnings count towards percentage-based benefits. Each entry sets a `type` (`earning`, `allowance`, or `reimbursement`) and a `subtype`. | | `amount` | Fixed contribution amount (optional) | | `percent` | Percent of eligible earnings (optional) | | `max_annual_contribution` | Optional annual contribution cap | | `max_annual_contribution_basis` | What the annual cap applies to. `this_benefit` caps this benefit on its own. `all_line_items_of_type` shares one cap across every benefit of the same type (for example, two separate RRSP plans count toward a single yearly limit). | | `coverage_multiplier` | Coverage multiplier used for life insurance plans. | | `remittance_account_id` | The remittance account these contributions are paid out to. | | `expense_accounting_code_id` | Accounting code that routes the expense side of this benefit. | | `liability_accounting_code_id` | Accounting code that routes the liability side of this benefit. | For the complete list of accepted fields, see the [Create an Employer Benefit](/api-reference/employer-benefits/create-an-employer-benefit) API reference. > πŸ” Note: employee\_benefit\_id is used only for UI grouping. No values are inherited, and changes to one do not affect the other. ## Employee Contributions Employee Benefits represent the configuration of recurring contributions deducted from the employees earnings towards benefit plans, such as health insurance or retirement contributions. * They can be fixed amounts or calculated based on employee earnings. * During the effective dates, these contributions are automatically applied to the payroll as an Employee Benefit Line Item. * Employee Benefits can be inherited from a Business Preset, allowing for consistent benefit configurations across multiple work assignments. ### Key Fields | Field | Description | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `work_assignment_id` | Required. The work assignment this benefit applies to. Must belong to a work assignment associated with an entity of type Employee. | | `business_preset_id` | Optional Business Preset to inherit from. | | `employee_benefit_type` | The type of benefit (e.g. `health`, `pension_rrsp`, `group_term_life_insurance`). Required unless inherited from a Business Preset. | | `employer_benefit_id` | Optional reference to an employer\_benefit used solely for display. | | `title` | Label for identifying the benefit. | | `effective_from` | Start date of the benefit. | | `effective_to` | The end date for this plan (optional) | | `frequency` | How often the benefit applies (e.g. `once`, `per_payroll`, `per_month`) | | `income_basis` | Income basis used for percentage-based benefits (`regular_earnings`, `total_income`) | | `income_includes` | Narrows which earnings count towards percentage-based benefits. Each entry sets a `type` (`earning`, `allowance`, or `reimbursement`) and a `subtype`. | | `amount` | Fixed contribution amount (optional) | | `percent` | Percent of eligible earnings (optional) | | `max_annual_contribution` | Optional annual contribution cap | | `max_annual_contribution_basis` | What the annual cap applies to. `this_benefit` caps this benefit on its own. `all_line_items_of_type` shares one cap across every benefit of the same type (for example, two separate RRSP plans count toward a single yearly limit). | | `coverage_multiplier` | Coverage multiplier used for life insurance plans. | | `remittance_account_id` | The remittance account these contributions are paid out to. | | `expense_accounting_code_id` | Accounting code that routes the expense side of this benefit. | | `liability_accounting_code_id` | Accounting code that routes the liability side of this benefit. | For the complete list of accepted fields, see the [Create an Employee Benefit](/api-reference/employee-benefits/create-an-employee-benefit) API reference. > πŸ” Note: employer\_benefit\_id is used only for UI grouping. No values are inherited, and changes to one do not affect the other. ## Validations * Only one of `amount` or `percent` may be set per benefit. Attempts to set both will result in a validation error. * A benefit must include a `*_benefit_type` unless inherited from a Business Preset. *** ## Contribution Limits Each benefit can have a `max_annual_contribution` defined to set an annual limit, which is enforced during payroll processing. * `max_annual_contribution_basis` sets what the annual cap applies to. `this_benefit` (the default) caps this benefit on its own. `all_line_items_of_type` shares one cap across every benefit of the same type, so two separate RRSP plans count toward a single yearly limit. * The limit resets at the start of each calendar year. * Only paid line items count towards the limit. * Historical Year-To-Date (YTD) contributions are not considered when calculating contributions towards the limit. ### Employer Benefit Line Items Employer Benefit Line Items represent the actual contributions made by the employer towards employee benefit plans during payroll processing. These line items are generated based on the configured Employer Benefits, or can be created directly for one-time contributions. | Field | Description | | ------------------------- | ------------------------------------------------------------------------------------------- | | `business_preset_id` | Optional Business Preset to inherit from. | | `employer_benefit_type` | The type of benefit (e.g. `health`, `pension_rrsp`, `group_term_life_insurance`) | | `recurrence` | The employer benefit which generated this line item (read-only) | | `title` | Label for identifying the benefit line item. | | `amount` | Actual dollar value for this line item (read-only) | | `custom_amount` | User settable value for the line item amount, always takes precedence over `managed_amount` | | `managed_amount` | The calculated value for this line item. | | `max_annual_contribution` | Optional annual contribution cap | | `coverage_multiplier` | Coverage multiplier used for life insurance plans. | *** ### Employee Benefit Line Items Employee Benefit Line Items represent the actual contributions made by the employee towards benefit plans during payroll processing. These line items are generated based on the configured Employee Benefits, or can be created directly for one-time contributions. | Field | Description | | ------------------------- | ------------------------------------------------------------------------------------------- | | `business_preset_id` | Optional Business Preset to inherit from. | | `employee_benefit_type` | The type of benefit (e.g. `health`, `pension_rrsp`, `group_term_life_insurance`) | | `recurrence` | The employee benefit which generated this line item (read-only) | | `title` | Label for identifying the benefit line item. | | `amount` | Actual dollar value for this line item (read-only) | | `custom_amount` | User settable value for the line item amount, always takes precedence over `managed_amount` | | `managed_amount` | The calculated value for this line item. | | `max_annual_contribution` | Optional annual contribution cap | | `coverage_multiplier` | Coverage multiplier used for life insurance plans. | *** ### Benefit Types Employee and employer benefits each have their own set of supported benefit types, which may overlap. You can retrieve the lists using the following endpoints: * `GET /employee_benefit_types`: Returns all employee benefit types * `GET /employer_benefit_types`: Returns all employer benefit types Each benefit type object includes: * `type`: the unique identifier used in the API, e.g. `critical_illness`, `pension_dcpp`. * `label`: a human-readable name for display purposes, e.g "Critical Illness", "Defined Contribution Pension Plan (DCPP)". *** ## Example Scenarios ### A. One-Time Dental Contribution Creates a one-time \$125 employee-only dental benefit: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/employee_benefits \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "...", "employee_benefit_type": "dental", "frequency": "once", "amount": 125, "effective_from": "2025-04-01", "title": "Employee Dental Plan Contribution" }' ``` *** ### Recurring Employee RRSP contribution A recurring RRSP contribution of \$150 each payroll with an annual maximum of \$600, starting from January 1, 2025: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/employee_benefits \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "...", "employee_benefit_type": "pension_rrsp", "frequency": "per_payroll", "amount": 150, "max_annual_contribution": 600, "effective_from": "2025-01-01" }' ``` *** ### Shared Health Plan A recurring Health contribution: * Employer contributes \$50 per payroll. * Employee contributes \$25 per payroll. * The two benefits are linked, allowing the two benefits to be displayed together in payroll. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/employer_benefits \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "...", "employer_benefit_type": "health", "frequency": "per_payroll", "amount": 50, "effective_from": "2025-01-01" }' ``` ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/employee_benefits \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "...", "employer_benefit_id": "", "employee_benefit_type": "health", "frequency": "per_payroll", "amount": 25, "effective_from": "2025-01-01" }' ``` # Deductions & Remittances Source: https://docs.nmbr.co/guides/payroll-fundamentals/deductions-and-remittances Nmbr enables automatic deduction handling on Pay Stubs for both Employees and Contractors. Some deductions are processed directly within the payroll and subsequently disbursed to the appropriate recipients. Others, while deducted during the payroll process, must be remitted by the Employer to the designated recipients. Below is a list of deductions Nmbr can calculate. | Deduction | Type | Recipient | Remitted by Nmbr | | :------------------------------------ | :-------------------: | --------: | ---------------- | | Federal Income Taxes | Statutory Withholding | CRA | βœ… | | Provincial Income Taxes | Statutory Withholding | CRA | βœ… | | Employee CPP contributions | Statutory Withholding | CRA | βœ… | | Employee EI premium | Statutory Withholding | CRA | βœ… | | Employer CPP contributions | Statutory Withholding | CRA | βœ… | | Employer EI premium | Statutory Withholding | CRA | βœ… | | Employee QPP contributions | Statutory Withholding | RQ | βœ… | | Employee QPIP premiums | Statutory Withholding | RQ | βœ… | | Employer QPP contributions | Statutory Withholding | RQ | βœ… | | Employer QPIP premiums | Statutory Withholding | RQ | βœ… | | Northwest Territories payroll taxes | Statutory Withholding | GNWT | βœ–οΈ | | Nunavut payroll taxes | Statutory Withholding | GNU | βœ–οΈ | | Union dues | Deduction | - | βœ–οΈ | | Income Garnishments | Deduction | CRA | βœ–οΈ | | Group term life insurance | Benefit | - | βœ–οΈ | | Group sickness and accident insurance | Benefit | - | βœ–οΈ | | Private Health insurance plans | Benefit | - | βœ–οΈ | | RRSPs | Benefit | - | βœ–οΈ | # Forms Source: https://docs.nmbr.co/guides/payroll-fundamentals/forms One API for the government forms Nmbr produces, from ROEs to T4s to TD1s Forms are the government documents you produce for payroll, like ROEs and T4s. They share one set of endpoints and one shape. Learn the shape once and it carries across every form. There are two things to keep straight: * A **form type** is the definition. It describes which fields exist, what they mean, and how to fill them in. `roe`, `t4`, and `td1on` are form types. * A **form** is one filled-in instance of a type, tied to an owner. A T4 for one employee is a form. ## Forms are self-describing The fields on a form are not a fixed schema you hard-code. They depend on the form type and its version, and they change over time as the government revises each form. So you don't build a T4 by memorizing its boxes. You ask the API what the current T4 looks like, then render and fill what it returns. This is the core idea: **the API hands you the field definitions at runtime, and you build against them.** A form editor built this way keeps working when a form gains a box or a new version ships. ## Listing form types Retrieve the available form types with the [List form types](/api-reference/form-types/list-form-types) endpoint. **Request** ```json theme={null} # GET /services/payroll/form_types ``` **Response** ```json theme={null} { "object": "list", "data": [ { "id": "roe", "object": "form_type", "data": { "type": "roe", "label": "Record of Employment", "owner_types": ["employee"] } }, { "id": "t4", "object": "form_type", "data": { "type": "t4", "label": "T4 Statement of Remuneration Paid", "owner_types": ["employee"] } } ] } ``` ## Retrieving a form type Retrieve one form type with the [Retrieve a form type](/api-reference/form-types/retrieve-a-form-type) endpoint to get its full definition: its version, its capabilities, and every field. **Request** ```json theme={null} # GET /services/payroll/form_types/roe?effective_date=2026-08-01 ``` **Response** ```json theme={null} { "id": "roe", "object": "form_type", "data": { "type": "roe", "label": "Record of Employment", "version_year": 2026, "version_month": "august", "owner_types": ["employee"], "supports_population": true, "supports_generation": true, "exportable_as": ["xml", "pdf"], "groups": { "employment_details": "Employment Details", "separation_information": "Separation Information" }, "fields": [ { "key": "block_10_first_day_worked", "label": "First Day Worked (Block 10)", "type": "date", "required": true, "readonly": false, "group": "employment_details" } ] } } ``` ### Field definitions Each entry in `fields` tells you how to render and handle one input: * `key`: the field to read and write, for example `block_10_first_day_worked`. This is the name you send back when you fill the form. * `label`: the display name. * `type`: which control to render. One of `text`, `numeric`, `currency`, `date`, `boolean`, or `select`. * `required`: whether to mark the input as required. * `readonly`: whether to disable the input. * `options`: for `select` fields, the allowed values as a map of value to label. Render these as the choices. * `group`: which section the field belongs to. The top-level `groups` map gives each group its heading. The grouping is a suggestion for laying out your form, and it may change. * `help`: guidance to show alongside the field, when the form provides it. A `select` field carries its own options: ```json theme={null} { "key": "block_6_pay_period_type", "label": "Pay Period Type (Block 6)", "type": "select", "required": true, "readonly": false, "options": { "W": "(W) Weekly", "B": "(B) Biweekly", "S": "(S) Semi-Monthly", "M": "(M) Monthly" }, "group": "employment_details" } ``` ### Versions and `effective_date` `effective_date` picks the version of the form. Governments revise their forms over time: new fields appear, a select gains options, claim amounts and validation rules change. Each revision is a new version, and the API resolves your `effective_date` to the version in effect on that date. Pass the date the form applies to and you always build against the right version. If you omit `effective_date`, it defaults to today. ### Owners `owner_types` tells you what a form attaches to. It's one or more of `employee`, `contractor`, or `work_assignment`. A T4 belongs to an employee; a TD1 belongs to a work assignment; a T4A can belong to either an employee or a contractor. You set the owner when you create the form, and the owner's type is inferred from its ID prefix (`emp_`, `ctr_`, `wrkas_`). ### Capabilities vary by form type Not every form supports every operation. Three fields on the definition tell you what a given form type can do: * `supports_population`: you can fetch suggested field values from the employee's payroll data. * `supports_generation`: the API can build completed forms for you in the background. * `exportable_as`: which file formats you can export, such as `xml` or `pdf`. An empty list means the form is not exportable. The range is wide. Here's how a few form types compare: | Form type | Owner | Populate | Generate | Export | Fields | | ---------------------------------------- | -------------------- | -------- | -------- | -------- | ------ | | Record of Employment (`roe`) | Employee | Yes | Yes | XML, PDF | 246 | | T4 (`t4`) | Employee | No | Yes | PDF | 85 | | T4A (`t4a`) | Employee, Contractor | No | Yes | PDF | 80 | | RL-1 (`rl1`) | Employee | No | Yes | PDF | 45 | | QuΓ©bec Source Deductions (`tp_1015_3_v`) | Work Assignment | No | No | None | 13 | | TD1 Ontario (`td1on`) | Work Assignment | No | No | None | 12 | ## Creating a form Create a form with the [Create a form](/api-reference/forms/create-a-form) endpoint. Send the `type` and the `owner_id`. You can set field values in the same request, or leave them empty and fill them later. **Request** ```json theme={null} # POST /services/payroll/forms { "type": "td1on", "owner_id": "wrkas_01HX3F7T8B2D", "line_1_basic_personal_amount": 12747.0 } ``` The response is the created form. Even if you set only one field, it returns every field for the form, unset ones as `null`. **Response** ```json theme={null} { "id": "form_01JSCE1S1CF5C0VFPZZVBS6X5R", "object": "form", "data": { "type": "td1on", "owner": { "id": "wrkas_01HX3F7T8B2D", "object": "work_assignment" }, "effective_date": "2026-01-01", "version_year": 2026, "version_month": "january", "is_editable": true, "validation_error_count": 0, "line_1_basic_personal_amount": 12747.0, "line_2_age_amount": null } } ``` A form's field values sit alongside its metadata in `data`. Read them by the same `key` the definition uses. ## Populating a form For form types where `supports_population` is `true`, the API can suggest field values from the employee's payroll data instead of you calculating them. Fetch the suggestions with the [Populate a form](/api-reference/form-types/populate-a-form) endpoint. **Request** ```json theme={null} # POST /services/payroll/form_types/roe/populate { "employee_id": "emp_01H7M9X2QV4N", "work_assignment_ids": ["wrkas_01HX3F7T8B2D"], "first_day_worked": "2026-01-06", "last_day_for_which_paid": "2026-07-31" } ``` **Response** ```json theme={null} { "object": "form_population_result", "data": { "fields": { "block_10_first_day_worked": "2026-01-06", "block_11_last_day_for_which_paid": "2026-07-31", "pp1_insurable_earnings": 1840.0 } } } ``` Population data is not saved on its own. Send the values you want to keep to the [Update a form](/api-reference/forms/update-a-form) endpoint to persist them. ## Generating forms For form types where `supports_generation` is `true`, the API can build completed forms for you: it creates each form and fills its fields from the owner's payroll data in one step. Start a run with the [Generate forms](/api-reference/form-types/generate-forms) endpoint. Generation runs in the background, so the endpoint returns an [async task](/api-reference/async-tasks/retrieve-an-async-task) rather than the forms. Poll the task or listen for the `async_task_completed` [webhook](/api/overview/webhook-structure) to know when it finishes. The webhook fires whether generation succeeded or failed, so fetch the task and check `status`: `completed` means every form was created, `error` means the run failed and any partially generated forms were removed. Each form type shapes its own request, and one request can create many forms. ## Reading and editing a form Retrieve a form with the [Retrieve a form](/api-reference/forms/retrieve-a-form) endpoint, and list a company's forms with [List forms](/api-reference/forms/list-forms). Two fields on a form tell you its editing state: * `is_editable`: whether the form can still be changed. A submitted form is not editable. * `validation_error_count`: how many fields currently fail validation. Change a form's fields with the [Update a form](/api-reference/forms/update-a-form) endpoint. Send only the fields you want to change. **Request** ```json theme={null} # PUT /services/payroll/forms/form_01JSCE1S1CF5C0VFPZZVBS6X5R { "line_1_basic_personal_amount": 13000.0 } ``` ## Validating a form Check a form's fields before submission with the [Validate a form](/api-reference/form-types/validate-a-form) endpoint. Send the form's `effective_date` and the fields you want to check. The `effective_date` picks the version to validate against, so use the form's own date. The response lists any errors, keyed by field. **Request** ```json theme={null} # POST /services/payroll/form_types/roe/validate { "effective_date": "2026-08-07", "block_10_first_day_worked": "2026-01-06", "pp1_insurable_earnings": 0.0 } ``` **Response** ```json theme={null} { "data": { "errors": { "pp1_insurable_earnings": ["pp1_insurable_earnings cannot be 0"] } } } ``` ## Submitting a form Submit a form with the [Submit a form](/api-reference/forms/submit-a-form) endpoint. What submission means depends on the form type. Some forms, like the ROE, are filed with a government agency and move through a status lifecycle (`draft`, `processing`, `submitted`, `done`, `rejected`). Others are records you complete and export yourself. See the form-specific guide for what a given form does on submission. ## Exporting a form For form types with a non-empty `exportable_as`, retrieve the file from the [Retrieve a form](/api-reference/forms/retrieve-a-form) endpoint by setting the `Accept` header to the format you want: * `Accept: application/pdf` for a PDF. * `Accept: application/xml` for XML. Without one of these headers, the endpoint returns the form as JSON. A format listed in `exportable_as` is not always available for every form. The ROE is the clearest example: a managed ROE exports as a PDF only once Service Canada has accepted it, and never as XML, because Nmbr files it for you. When a format is not available for a given form, the endpoint returns `406 Not Acceptable`. The form-specific guides spell out the conditions. ## Form-specific guides Each form type builds on everything above and adds its own rules, request shapes, and submission behaviour: * [Record of Employment (ROE)](/guides/canada/record-of-employment) * [Year-end tax forms (T4, T4A, RL-1)](/guides/canada/year-end-tax-forms) * [TD1 tax credit forms](/guides/payroll-fundamentals/td1-forms) # Importing Hours Source: https://docs.nmbr.co/guides/payroll-fundamentals/importing-hours Updating hours worked for individual employees or contractors ## Updating hours worked The Nmbr API surfaces an endpoint that can be used to import hours for many employees at once. ### Supported Earning Types The supported earning line item types are: * `wage` (multiple require a `pay_rate_id` and/or `earned_on`) * `salary` (multiple require a `pay_rate_id` and/or `earned_on`) * `overtime` (multiple require an `overtime_rate_id`, `rate_multiplier`, and/or `earned_on`) * `vacation_pay` (multiple require a `pay_rate_id` and/or `earned_on`) ### Simple Scenario In this simple scenario, each employee has been configured with a single Pay Rate. To run payroll accurately, you will be required to update the hours for each Earning Line Item generated from the Pay Rates. To cut down on API calls, use the `POST /payrolls/{payroll}/hours` endpoint to import hours for multiple employees at once. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//hours \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "data": [ { "work_assignment_id": "wrk_001", "wage": [ { "hours": 10 } ] }, { "work_assignment_id": "wrk_002", "wage": [ { "hours": 15 } ] } ] }' ``` ### A More Complex Scenario In some cases, employees may have multiple Pay Rates and Overtime Rates, resulting in many Earning Line Items. In order for the system to know which hours correspond with each Earning Line Item, the API requires you to provide either a `pay_rate_id`, `overtime_rate_id`, or `rate_multiplier`, depending on the type of earning. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//hours \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "data": [ { "work_assignment_id": "wrk_001", "salary": [ { "pay_rate_id": "pay_000", "hours": 40 } ], "wage": [ { "pay_rate_id": "pay_001", "hours": 10 }, { "pay_rate_id": "pay_002", "hours": 15 } ], "overtime": [ { "rate_multiplier": 1.5, "hours": 3 }, { "rate_multiplier": 2, "hours": 6 }, { "overtime_rate_id": "ovr_001", "hours": 1 } ], "vacation_pay": [ { "pay_rate_id": "pay_001", "hours": 5 } ] } ] }' ``` ### Tracking Hours by Date If you track hours per day (or any other date granularity within the payroll period), you can attach an `earned_on` date to each entry. This is supported on every earning type. The `earned_on` value: * Must be a date that falls within the payroll's pay period. * Is part of the entry's scoping key, so you can submit multiple entries against the same `pay_rate_id` (or `overtime_rate_id` / `rate_multiplier`) as long as their `earned_on` dates differ. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//hours \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "data": [ { "work_assignment_id": "wrk_001", "wage": [ { "pay_rate_id": "pay_001", "hours": 8, "earned_on": "2026-04-13" }, { "pay_rate_id": "pay_001", "hours": 8, "earned_on": "2026-04-14" }, { "pay_rate_id": "pay_001", "hours": 6, "earned_on": "2026-04-15" } ], "overtime": [ { "rate_multiplier": 1.5, "hours": 2, "earned_on": "2026-04-15" } ] } ] }' ``` ### Targeting a Business Preset When you import hours for distinct configured workflows that share an earning type and rate, include `business_preset_id` on each earning entry. The preset identifies which line item to update or create. The preset must belong to the payroll's business entity, have the `earning` type, and match the entry's earning type when the preset has a subtype. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//hours \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "data": [ { "work_assignment_id": "", "vacation_pay": [ { "pay_rate_id": "", "business_preset_id": "", "hours": 8 }, { "pay_rate_id": "", "business_preset_id": "", "hours": 4 } ] } ] }' ``` The preset is part of the matching key. Re-send the same earning type, rate, date, and preset to update the same line item. Use a different compatible preset to keep the line items separate. Requests without `business_preset_id` keep their existing matching behaviour. See [Presets](/guides/advanced/presets) to create and manage Business Presets. # Line Item Type Features Source: https://docs.nmbr.co/guides/payroll-fundamentals/line-item-type-features Line item types include earning types, deduction types, allowance types, reimbursement types, and employee and employer benefit types. Different Line Item types in Nmbr have different effects on payroll calculations, depending on multiple factors including: * the type of line item * the Work Assignments Province Of Employment (POE) * the tax documents which have been completed You can use the Nmbr API to get an overview of the ways in which different line item types are treated in payroll calculations. ## Payroll Features Query When using the Line Item Types APIs, you may pass a `features` query parameter with the value `ca`. The response will then contain a `features` array, which details how each line item type is treated in payroll calculations. This query can be used with the following endpoints: * [List Earning Types](/api-reference/earning-types/list-earning-types) * [List Allowance Types](/api-reference/allowance-types/list-allowance-types) * [List Deduction Types](/api-reference/deduction-types/list-deduction-types) * [List Reimbursement Types](/api-reference/reimbursement-types/list-reimbursement-types) * [List Employee Benefit Types](/api-reference/employee-benefit-types/list-employee-benefit-types) * [List Employer Benefit Types](/api-reference/employer-benefit-types/list-employer-benefit-types) **Request** ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/earning_types/salary?features=ca \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' ``` **Response** ```json theme={null} { "id": "salary", "object": "earning_type", "data": { "type": "salary", "label": "Salary", "supported_payroll_types": { "regular": true, "historical": true, "off_cycle": true }, "features": [ { "type": "income_tax", "label": "Income Tax", "definitions": [ { "jurisdiction": "ca_federal", "effects": [ "withholding" ], "help_text": null, "program_label": null } // ... ] } ] } } ``` ## Definitions Each entry in the `features` array contains: * `type`: The type of payroll feature. * `definitions`: Details on how the line item type is treated for each jurisdiction. These fields are informational and don’t describe rates, thresholds, or full calculation logic. If an entry is missing for a given jurisdiction, it means that the line item type has no effect for that payroll treatment in that jurisdiction. ### Payroll feature types The possible values for the `type` field are: * `income_tax`: Federal and Provincial/Territorial Income tax withholding calculations. * `pensionable`: Federal and Quebec pension plans, such as the Canada Pension Plan (CPP) and Quebec Pension Plan (QPP). * `insurable`: Federal and Quebec insurance plans, such as the Employment Insurance (EI) and Quebec Parental Insurance Plan (QPIP). * `wcb`: Workers' Compensation Board contributions, which vary by province. * `eht`: Employer Health Tax contributions, applicable in certain provinces. * `vacationable`: Provincial rules for vacation pay accrual on remuneration. ### Definition fields Each entry in the `definitions` array contains: * `jurisdiction`: The jurisdiction to which the definition applies, e.g. `ca_federal`, `ca_on`, `ca_bc`, etc. * `effects`: An array of effects that the line item type has for the given jurisdiction and payroll feature type. Possible effects include: * `withholding`: The line item type is included in the calculation base for withholding calculations. * `reduces_base`: The line item type reduces the base amount for the given payroll feature. * `tax_credit`: The line item type provides a tax credit for the given payroll feature. * `accrues_vacation_pay`: The line item type accrues vacation pay. * `help_text`: Additional information or context about the feature, if applicable. * `program_label`: The specific program or plan label associated with the feature, if applicable. E.g., "CPP", "EI", etc. # Managing Pay Schedules Source: https://docs.nmbr.co/guides/payroll-fundamentals/managing-pay-schedules ## Overview A payroll schedule determines the length of your pay period and how often you pay your employees. The most common payroll schedules are weekly, biweekly, semimonthly, and monthly. Your payroll schedule is dependent upon a few factors, including provincial laws and regulations. Many provinces have pay schedule frequency requirements that you’ll need to meet. On top of provincial laws, your pay schedule should also fit the needs of your employees and your business. If you employ mostly hourly workers, your pay schedule may look different from a business with mostly salaried employees. Your province, your industry, and the types of workers you employ all impact your payroll schedule. Typical pay frequencies include: * Weekly * Bi-weekly * Semi-monthly * Monthly Each frequency type requires specific configuration parameters. *** ## Pay Schedule Parameters | Field | Type | Required | Description | | -------------------------- | ------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `title` | string | Yes | The label used for this Pay Schedule. | | `pay_frequency` | enum | Yes | Must be one of `weekly`, `bi-weekly`, `semi-monthly`, `monthly` or `custom`. | | `anchor_pay_date` | ISO8601 date (YYYY-MM-DD) | Yes | First intended pay date (before weekend/holiday movement). | | `anchor_end_of_pay_period` | ISO8601 date (YYYY-MM-DD) | Yes | Final day of the first earning period. | | `day_1` | integer | Conditional | On `monthly` or `semi-monthly` schedules, the numeric day of month for the first payroll. | | `day_2` | integer | Conditional | On `semi-monthly`, the numeric day in the month for the second payroll. | | `pay_day_movement_setting` | enum | No | Determines how pay dates are adjusted for holidays or weekends. Defaults to `inherit`. | | `generate_payrolls_from` | ISO8601 date (YYYY-MM-DD) | No | Available for Business Entities in Preview mode, must be on or after `anchor_pay_date`. Allows for creation of Payrolls before the current date. | ### Pay Day Movement Options * `inherit` (default): Use the Business Entity setting. * `previous_business_day`: Move to the previous working day. * `next_business_day`: Move to the next working day. ### Custom Pay Schedules For more information on Custom Pay Schedules, please see the\ [Custom Pay Schedules](/guides/advanced/custom-pay-schedules) guide. *** ## Creating a Pay Schedule ### Endpoint `POST /services/payroll/pay_schedules` ### Request Example ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_schedules \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "title": "Salary Schedule", "pay_frequency": "semi-monthly", "anchor_pay_date": "2025-01-15", "anchor_end_of_pay_period": "2025-01-15", "day_1": 15, "day_2": -1, "business_entity_id": "01hhcy3fpqkez7wjqzeaqetwfs" }' ``` ### Success Response ```json theme={null} { "id": "01hhcy3ftxe4wrcsyzf7a3a46q", "object": "pay_schedule", "data": { "title": "Salary Schedule", "pay_frequency": "semi-monthly", "anchor_pay_date": "2025-01-15", "anchor_end_of_pay_period": "2025-01-15", "day_1": 15, "day_2": -1, "pay_day_movement_setting": "inherit", "created_at": "2025-12-11T17:16:56Z", "updated_at": "2025-12-11T17:16:56Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_schedules/01hhcy3ftxe4wrcsyzf7a3a46q" } } ``` ### Error Response Example ```json theme={null} { "message": "The selected pay frequency is invalid (and 1 more error)", "errors": { "pay_frequency": [ "The selected pay frequency is invalid." ], "anchor_pay_date": [ "The anchor pay date field is required unless pay frequency is in custom." ] } } ``` *** ## Behavior by Pay Frequency ### Weekly * Projects payrolls weekly based on the weekday value of `anchor_pay_date` and `anchor_end_of_pay_period`. ### Bi-Weekly * Projects payrolls every two weeks based on the weekday value of `anchor_pay_date` and `anchor_end_of_pay_period`. ### Semi-Monthly * Two pay periods per month. * Supports two configurations: * 15th and last day of the month - `day_1` of `15`, `day_2` of `-1`. * 16th and 1st of the month - `day_1` of `16`, `day_2` of `1`. * If `day_1` or `day_2` would fall on an invalid date (e.g., September 31st), the payroll's `calculated_pay_date` will be adjusted to the prior valid date. ### Monthly * One payroll per month. * `day_1` defines the pay date. Use `-1` to indicate *"last day of the month"*. * If `day_1` would fall on an invalid date (e.g., September 31st), the payroll's `calculated_pay_date` will be adjusted to the prior valid date. *** ## Notes * **Date Validations:** Invalid dates automatically roll back to the nearest valid day. * **Pay Date adjustment:** If the payrolls `calculated_pay_date` falls on a weekend or holiday, the payrolls `pay_date` will be adjusted to a valid date based on the `pay_day_movement_setting`. * **Defaults:** If `pay_day_movement_setting` is not provided, the Business Entity default is used. # Payments Source: https://docs.nmbr.co/guides/payroll-fundamentals/payments Understand how Nmbr moves money after a payroll is approved. When a Payroll is approved, Nmbr automatically generates a set of **payments** that represent every scheduled money movement for that Payroll. Payments give you full visibility into the flow of funds β€” from the employer's bank account, through Nmbr, and out to employees and tax agencies. ## How payments are generated You do not create payments directly. When you call the [approve endpoint](/api-reference/payrolls/approve-a-payroll), Nmbr calculates the amounts owed and generates a payment for each destination: * **Funding (payroll float)** β€” A debit from the employer's bank account to fund the entire Payroll. This is always the first payment to be processed. * **Employee payments** β€” A credit to each employee's or contractor's bank account for their net pay. * **Remittances** β€” Credits to the Canada Revenue Agency (CRA), Revenu QuΓ©bec (RQ), or other remittance accounts for statutory withholdings and employer contributions. Each payment includes a `process_at` date (when Nmbr submits the payment to the banking network) and an `expected_at` date (when the funds are expected to arrive). ## Payment lifecycle Every payment moves through a series of statuses as it is processed: ### pending The payment has been generated but has not yet been submitted to the banking network. ### processing Nmbr has submitted the payment to the banking network. The funds are in transit and the payment can no longer be modified. ### paid The payment has settled successfully. Funds have arrived at their destination. ### failed The payment was returned by the banking network. Common causes include non-sufficient funds (NSF) or an invalid bank account. When a funding payment fails, Nmbr will cancel the associated employee and remittance payments for that Payroll to prevent further issues. > When a payment fails, the parent Payroll's status is updated to reflect the failure. You can monitor payroll-level status changes via [webhooks](/api/overview/webhook-structure) or by polling the [payroll endpoint](/api-reference/payrolls/retrieve-a-payroll). ### overdue A payment that was held past its `process_at` date transitions to `overdue`. Overdue payments cannot be released through the API and must be resolved through Nmbr support. ## Holding and releasing payments Partners can place a **hold** on any payment. What a hold means depends on when it is placed: * **Before processing** (pending payments) β€” The payment is blocked from being submitted to the banking network. It will not process until released. * **After settlement** (paid payments) β€” The payment itself is not reversed β€” it has already settled. However, holding a settled funding payment blocks all downstream payments (employee, CRA, RQ) from being processed. This is useful for verification before releasing funds to employees. ### Placing a hold Any payment can be held regardless of its status or destination. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payments//hold \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` ### Releasing a hold Any held payment can be released. Once released, the payment returns to normal processing and pending payments will be submitted in the next processing window. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payments//release \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` ### Automatic verification holds Business Entities can be configured with `hold_funding_for_verification` to automatically hold funding payments after they settle. This gives bank partners time for internal monitoring before downstream payments proceed. Downstream payments remain blocked until the hold is released. ## Querying payments Retrieve all payments for a Business Entity using the [list payments endpoint](/api-reference/payments/list-payments). You can filter by `status`, `destination`, `method`, `payroll_id`, and `is_held` to narrow down results. ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/payments?business_entity_id=&status=pending' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` ## Key concepts for integrators * **Payments are read-only.** You cannot create, update, or delete payments directly. They are generated and managed by Nmbr as part of the payroll lifecycle. * **Funding must settle first.** Employee and remittance payments are only processed after the funding payment has settled and is not held. * **Failed funding cascades.** If the employer's funding payment fails, all related employee and remittance payments for that Payroll are automatically canceled. * **Monitor status via webhooks.** Subscribe to payroll status webhooks to be notified when payments move through processing stages, rather than polling the API. # Payroll Lifecycle Source: https://docs.nmbr.co/guides/payroll-fundamentals/payroll-lifecycle Stages in the lifecycle of a Payroll Nmbr will automatically generate payrolls and pay stubs for configured pay schedules and employment profiles. The next payroll in the pay schedule, ordered by `pay_date`, will automatically have all recurring earnings, allowances, reimbursements, deductions and benefits populated on its Pay Stubs. ## Interacting with payrolls You can retrieve a list of payrolls from the payroll API endpoint: **Request** ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/payrolls \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` You can retrieve an individual payroll by querying for a specific ID: **Request** ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/payrolls/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "id": "01hfvzcp9c5phwfjkcra40rsg4", "object": "payroll", "data": { "type": "regular", "period_start": "2023-01-01T00:00:00.000000Z", "period_end": "2023-01-15T00:00:00.000000Z", "pay_date": "2023-01-13T00:00:00.000000Z", "employee_summary": { "gross": 1161.54, "subtractions": 449.23, "reimbursements": 0, "net": 712.31 }, "contractor_summary": { "gross": 100, "reimbursements": 15, "net": 115 }, "company_summary": { "taxes_and_contributions": 73.56, "benefits": 50, "total": 123.56 }, "liability": 1150.1, "cash_requirement": 1150.1, "status": "draft", "approved_at": null, "created_at": "2023-11-22T16:56:38.000000Z", "updated_at": "2023-11-22T16:56:38.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/payrolls/01hfvzcp9c5phwfjkcra40rsg4" } } ``` `employee_summary.subtractions` is the total of everything withheld from the employee's gross to reach net pay β€” statutory withholdings (income tax, CPP, EI), deductions (e.g. union dues), and the employee's benefit contributions. Each Pay Stub carries a per-employee `employee_summary`, a `company_summary`, and a `line_item_summary` that breaks the totals down by category β€” earnings, statutory withholdings, deductions, employee and employer benefits, reimbursements, and allowances. Query the pay stub endpoint for the Pay Stubs on a specific payroll id: **Request** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/pay_stubs?payroll_id=' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ ``` **Response** ```json theme={null} { "id": "01hfwg2784vc1408yhmjp4x81q", "object": "pay_stub", "data": { "payroll": { "id": "01hfvzcp9c5phwfjkcra40rsg4", "object": "payroll", "links": { "self": "https://sandbox.nmbr.co/services/payroll/payrolls/01hfvzcp9c5phwfjkcra40rsg4" } }, "work_assignment": { "id": "01hfwg1t8v9m2c3q7pk4d5znab", "object": "work_assignment", "links": { "self": "https://sandbox.nmbr.co/services/payroll/work_assignments/01hfwg1t8v9m2c3q7pk4d5znab" } }, "payment_method": "direct_deposit", "has_taxes_calculated": true, "is_pending_tax_rates": false, "employee_summary": { "gross": 2520, "subtractions": 594.91, "reimbursements": 10, "net": 1935.09, "gross_ytd": 2520, "subtractions_ytd": 594.91, "reimbursements_ytd": 10, "net_ytd": 1935.09 }, "contractor_summary": { "gross": null, "reimbursements": null, "net": null, "gross_ytd": 0, "reimbursements_ytd": 0, "net_ytd": 0 }, "company_summary": { "taxes_and_contributions": 180, "benefits": 40, "total": 220, "taxes_and_contributions_ytd": 180, "benefits_ytd": 40, "total_ytd": 220 }, "vacation_pay_balance": 0, "liability": 2750, "cash_requirement": 2750, "note": null, "line_item_summary": { "earnings": { "period": 2520, "period_managed": 2520, "period_unmanaged": 0, "ytd": 2520 }, "statutory_withholdings": { "period": 534.91, "ytd": 534.91 }, "reimbursements": { "period": 10, "ytd": 10 }, "allowances": { "period": 0, "ytd": 0 }, "employee_benefits": { "period": 40, "ytd": 40 }, "employer_benefits": { "period": 40, "ytd": 40 }, "deductions": { "period": 20, "ytd": 20 } }, "is_stale": false, "stale_since": null, "warnings": { "object": "list", "data": [] }, "external_ref": null, "apply_standard_tax_reductions": false, "created_at": "2023-11-22T21:48:01.000000Z", "updated_at": "2023-11-23T15:51:21.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/01hfwg2784vc1408yhmjp4x81q" } } ``` ### Filtering the payrolls list `GET /payrolls` requires either a `business_entity_id` or a `pay_schedule_id`. Without one of them, the request returns a `422`. The `status` filter accepts one or more comma-separated values. Pass several to retrieve everything in flight in a single call: **Request** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/payrolls?business_entity_id=&status=draft,approved,processing' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` Invalid status values are rejected with a `422`. To retrieve every payroll except certain statuses, use `not_status` with the same comma-separated form: **Request** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/payrolls?business_entity_id=¬_status=draft,paid' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` Unknown values passed to `not_status` are ignored rather than rejected, so check them against the documented statuses. ### Retrieving the upcoming regular draft payroll To retrieve the upcoming regular draft payroll β€” the next payroll that is ready for editing β€” filter the payrolls index by `type=regular` and `status=draft`, and sort by `pay_date`: **Request** ```bash theme={null} curl --request GET \ --url 'https://sandbox.nmbr.co/services/payroll/payrolls?business_entity_id=&type=regular&status=draft&sort=pay_date:asc' \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` The first payroll in the response is the upcoming regular draft payroll. The `type=regular` filter returns regular payrolls only. Off-cycle and historical payrolls are excluded, so query them separately if you need them. > πŸ“˜ Why not use `next_payrolls`? > The `next_payrolls=only` filter returns the current payroll being handled by Nmbr for each Pay Schedule β€” which may be an `approved`, `processing`, or `failed` payroll, not necessarily one that is ready for editing. > Filtering by `type=regular&status=draft` and sorting by `pay_date` ensures you always get the next editable regular payroll. You can update an individual payroll line item using the API. The example below could be used to enter 10 hours for the given pay rate. ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/earnings/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "id": "01hc2p95nqdbz1ss6b90yf8zjv", "earning_type": "hourly", "amount": 100, "hours": 10, "accrued_vacation_pay": 2 }' ``` ## Approving payroll When a payroll is approved (via the `/payrolls//approve` endpoint), its status changes to approved. Once approved, the payroll can no longer be modified. This is because the taxes, net pay, and benefits have been calculated and saved for the payroll. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/payrolls//approve \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` > πŸ“˜ Rejected Approvals > If a payroll is in an invalid state when the `/approve` endpoint is called, the approval will fail, returning a `422 Unprocessable Entity` response. > Common reasons for failure include: > > * The payroll is past its approval date. > * A pay stub has a negative net amount. > * The payroll is not in the `draft` status. Once a payroll is approved, Nmbr will automatically collect funds from the employer's bank account, make sure wages are transferred into employees' bank accounts on payday, and remit tax payments on time. We handle all of this behind the scenes, but you will still want to keep tabs on your payroll as it moves through each phase of its lifecycle. Nmbr surfaces status information on the payroll objects returned by our API through the status field. A payroll can have one of five statuses: draft, approved, processing, paid, and failed. Below is an overview of these statuses, what they mean, and how payrolls transition between them. > πŸ“˜ Payroll status webhooks > When a payroll makes status transitions from approved to processing and from processing to paid, you can receive webhook notifications from our platform. See the webhook documentation for more details about how to set this up. ## Payroll Status Lifecycle ### draft When a payroll is first created, it will be in the draft status. You can modify a draft payroll in any way you see fit. Payments to employees can be added and removed, earnings and hours worked can be modified on individual payroll items, etc. You can only delete a payroll while it's in draft. ### approved When a payroll is approved (via the `/payrolls//approve` endpoint), its status changes to approved. Once approved, the payroll can no longer be modified. This is because the taxes, net pay, and benefits have been calculated and saved for the payroll. If you determine that an error exists in the payroll, you can move it back to the draft status (via the `/payrolls//unapprove` endpoint). Once back in draft, the payroll can again be modified, previewed, and even deleted. If and when it is approved again, the payroll moves back into the approved status. ### processing At the end of each business day at 5pm PT, our system collects all pending payrolls that have an approval deadline on that day and begins the multi-step process of moving money through the banking system to pay them out. The first step in this process is to submit an ACH transaction to debit the cash requirement for a payroll from the employer’s bank account. When a payroll’s debit transaction has been sent to the ACH network, it moves into a new status: processing. Once a payroll is processing, it can no longer be moved back to draft. If you require a change to a processing payroll, reach out to us directly. ### paid Due to the nature of the ACH network, the employer debit transaction will take 3 business days to complete. For example, if you approve a payroll with a Friday payday on Monday, we should have the employer’s funds in our bank account by Thursday morning. Once Nmbr has the employer’s cash requirement, we submit ACH transactions to send net pay to each employee who is set up for direct deposit. When these transactions complete, the payroll enters its final status: paid. Once here, the employees' payments for your payroll have been sent out . The employees are happy, and employers can focus on their business! ### partially\_paid **Deprecated.** No payroll reaches this status today, and you should not filter on it. It remains a valid value only for backwards compatibility. When an ACH payment to an employee or a contractor is returned (most often from an invalid account or routing number, or a frozen bank account), Nmbr marks that individual payment as failed and leaves the parent payroll in `processing`. There is no payroll-level "partially paid" signal. To find failures, check the child payment records for a `failed` status, then reach out to us directly to resolve one. ### failed Just as we will unfortunately see times that an employee's payment will fail, there will also be times when the ACH transaction to debit the cash requirement for an employer's payroll will be returned. One common reason this occurs is because there are insufficient funds for the transaction in an employer's bank account at the time of request. When this happens, Nmbr sets the payroll's status to be failed and, if possible, pauses in-flight employee and contractor payments for that payroll. Our team then works with you to quickly wire the cash requirement for the failed payroll before unpausing and delivering the payroll's employee and contractor payments. # Reporting Source: https://docs.nmbr.co/guides/payroll-fundamentals/payroll-reporting Nmbr supports asynchronous reports for payroll, remittance, accounting, tax form, and jurisdiction workflows. The example below creates a Liability Report, which can encompass liabilities across payrolls within a single business entity, a specific pay schedule, or a single payroll. Liability reports categorize liabilities by type and associated [Remittance Accounts](/api-reference/remittance-accounts/create-a-remittance-account). **Generate Report** Generate a Liability Report using the [Create Reports](/api-reference/reports/create-liability-report) endpoint. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/reports/liability \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_schedule_id": "", "filters": { "payroll_type":"regular", "payroll_status":["paid"], "pay_date_from":"2024-01-31", "pay_date_to":"2024-12-31" } }' ``` The response includes a Report ID (`report_ulid`), which is necessary to retrieve the completed report. ```json theme={null} { "id": "", "object": "report", "data": { "type": "liability", "business_entity": null, "pay_schedule": { "id": "", "object": "pay_schedule", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_schedules/" } }, "payroll": null, "filters": { "payroll_type": ["regular"], "payroll_status": ["paid"], "pay_date_from": "2024-01-31", "pay_date_to": "2024-12-31" }, "has_results": false, "created_at": "2024-06-25T20:53:33.000000Z", "updated_at": "2024-06-25T20:53:35.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/reports/" } } ``` **Retrieving a Report** The report results will be generated shortly after the report was created. Once it is ready (`has_results` is `true`), it can be retrieved through the [Retrieve Report](/api-reference/reports/retrieve-a-report) endpoint. The report data can be accessed as a CSV file by specifying the `Accept: text/csv` header. ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/reports/ \ --header 'Authorization: Bearer ' \ --header 'Accept: text/csv' ``` # Province of Employment and Province of Work Source: https://docs.nmbr.co/guides/payroll-fundamentals/province-of-employment > 🚧 Deprecation Notice\ > This document outlines the new Tax Property–based approach for managing Province of Employment. A previous method of configuring a Province of Employment directly on a Business Entity or Work Assignment is deprecated and will be removed in a future release. Please see the migration guide in the [section below](#deprecated-province-of-employment-configuration). When an employer pays employees income such as salaries, wages, or commissions, the employee's Province of Employment (POE) and Province of Work (POW) must be correctly configured to ensure the proper deductions are withheld. The Province of Employment (POE) determines the application of: * Provincial income taxes * Provincial sales taxes on benefits * EHT contributions The Province of Work (POW) determine the application of: * Vacation pay * Statutory holiday pay * WCB premiums ## Province of Employment (POE) ### Province of Employment on Business Entities When creating a Business Entity, it is essential to set a default Province of Employment. This POE will be used to calculate the appropriate withholdings on all Work Assignments in the Business Entity by default. To configure the Province of Employment on the Business Entity, you must create a [Tax Property](/guides/payroll-fundamentals/tax-properties) with a `type` of `ca::province_of_employment`, and `owner_id` of the Business Entity. > ❗️️Blocked Payrolls\ > Payroll approval will be blocked by a [Warning](/api/overview/warnings) if a Business Entity does not have a Province of Employment configured. See [Managing Tax Properties](#managing-tax-properties) for details on how to create or update the Province of Employment. ### Province of Employment on Work Assignments If an Employee's Work Assignment should use a different Province of Employment than the Business Entity, a Tax Property should be configured for the Work Assignment in question. To configure the Province of Employment on the Work Assignment, you must create a [Tax Property](/guides/payroll-fundamentals/tax-properties) with a `type` of `ca::province_of_employment`, and `owner_id` of the Work Assignment. This Tax Property will take precedence over any POE configured at the Business Entity level. See [Managing Tax Properties](#managing-tax-properties) for details on how to create or update the Province of Employment. ## Province of Work (POW) By default, an Employee's Work Assignment will use its Province of Employment as its Province of Work. If the Work Assignment should use a *different* Province of Work, a Tax Property should be configured for the Work Assignment in question. To configure the Province of Work on the Work Assignment, you must create a [Tax Property](/guides/payroll-fundamentals/tax-properties) with a `type` of `ca::province_of_work`, and `owner_id` of the Work Assignment. See [Managing Tax Properties](#managing-tax-properties) for details on how to create or update the Province of Work. ## Managing Tax Properties A Province of Employment Tax Property has the following attributes: | Field | Type | Required | Description | | ---------------- | --------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | | `owner_id` | string (Nmbr ULID) | βœ… Yes | The ID of the Business Entity or Work Assignment that you are configuring the POE for. | | `type` | string | βœ… Yes | Use `ca::province_of_employment`. | | `value` | string | βœ… Yes | See below for more details on valid values. | | `effective_from` | date string (`Y-m-d`) | βœ… Yes | The date this POE will take effect. See below for recommendations when setting this on newly created Business Entities. | | `effective_to` | date string (`Y-m-d`) | ❌ no | The final date this POE will be used. | Similarly, a Province of Work Tax Property has the following attributes: | Field | Type | Required | Description | | ---------------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `owner_id` | string (Nmbr ULID) | βœ… Yes | The ID of the Work Assignment that you are configuring the POW for.

Note: Unlike POE, you can only create a POW Tax Property for a Work Assignment, not a Business Entity. | | `type` | string | βœ… Yes | Use `ca::province_of_work`. | | `value` | string | βœ… Yes | See below for more details on valid values. | | `effective_from` | date string (`Y-m-d`) | βœ… Yes | The date this POW will take effect. See below for recommendations when setting this on newly created Business Entities. | | `effective_to` | date string (`Y-m-d`) | ❌ no | The final date this POW will be used. | For both POE and POW: * `effective_from`: When creating the first Province of Employment for a new Business Entity, it is suggested that the `effective_from` is set as the first day of the current year - e.g `2025-01-01`. This can help avoid issues when onboarding companies with `historical` payrolls dated before their transition to Nmbr. * `value`: The `value` can be any of: * `ca_ab` - Alberta * `ca_bc` - British Columbia * `ca_mb` - Manitoba * `ca_nb` - New Brunswick * `ca_nl` - Newfoundland and Labrador * `ca_ns` - Nova Scotia * `ca_nt` - Northwest Territories * `ca_nu` - Nunavut * `ca_on` - Ontario * `ca_pe` - Prince Edward Island * `ca_qc` - Quebec * `ca_sk` - Saskatchewan * `ca_yt` - Yukon The Tax Properties for Province of Employment and Province of Work do not support overlapping effective dates for the same owner. This means that before you can assign a new POE or POW to a Business Entity or Work Assignment, you must first end the current one by setting its `effective_to` date. When ending the Tax Property, you can use the `earliest_valid_effective_to` attribute to simplify selecting the new `effective_to` date. The `earliest_valid_effective_to` is the first date where this Tax Property has not been used on any non-draft Payroll (e.g. with a status of `approved` or `paid`) - as it is not possible to change the POE or POW on data in the past. Dates prior to `earliest_valid_effective_to` are considered invalid and will be rejected by the API. To avoid gaps that could result in payroll calculation errors, the `effective_from` date of the new Province of Employment or Province of Work should be set to the day immediately following the `effective_to` date of the previous one. If a Work Assignment’s Province of Employment is ended without a new one being assigned, it will automatically inherit the Province of Employment from the associated Business Entity. If a Work Assignment’s Province of Work is ended without a new one being assigned, it will automatically inherit the Province of Employment from the Work Assignment. If the Work Assignment's POE has also been ended, it will inherit the POE from the associated Business Entity, as above. ## Example Usage Creating a Province of Employment for a Business Entity: ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "type": "ca::province_of_employment", "value": "ca_mb", "effective_from": "2026-01-01" }' ``` ```json theme={null} { "id": "txprp_01JV378Q2EDB8H720QW2KZ2QFJ", "object": "tax_property", "data": { "type": "ca::province_of_employment", "value": "ca_mb", "effective_from": "2026-01-01", "effective_to": null, "earliest_valid_effective_to": "2026-01-01", "is_editable": true, "is_deletable": true, "label": "Province Of Employment", "format": "string", "options": { "ca_ab": "Alberta", "ca_bc": "British Columbia", "ca_mb": "Manitoba", "ca_nb": "New Brunswick", "ca_nl": "Newfoundland and Labrador", "ca_ns": "Nova Scotia", "ca_nt": "Northwest Territories", "ca_nu": "Nunavut", "ca_on": "Ontario", "ca_pe": "Prince Edward Island", "ca_qc": "Quebec", "ca_sk": "Saskatchewan", "ca_yt": "Yukon" }, "allow_concurrent": false, "feature": "onboarding", "owner": { "id": "be_01JN4M4FN41P11NQ1WS130Z2HT", "object": "business_entity", "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/be_01JN4M4FN41P11NQ1WS130Z2HT" } }, "note": null, "created_at": "2025-05-12T21:43:56.000000Z", "updated_at": "2025-05-12T21:43:56.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/tax_properties/txprp_01JV378Q2EDB8H720QW2KZ2QFJ" } } ``` ## Outside Canada (oc) Under certain circumstances, a Business Entity or Work Assignment may have its Province of Employment or Province of Work set to Outside Canada (OC). Nmbr supports OC as a valid value for the Province of Employment and Province of Work Tax Properties (`ca_oc`). This corresponds to the CRA rules for a province of employment of β€œOutside Canada.” When Outside Canada is set as the Province of Employment, Nmbr will not calculate any provincial/territorial income taxes or EHT (or similar provincial payroll taxes) for the affected Work Assignments. Only the following statutory withholdings are calculated (where the employment is pensionable/insurable under CPP/EI, as per CRA guidelines): * Federal income tax * Canada Pension Plan (CPP) contributions * Employment Insurance (EI) premiums By default, Nmbr will withhold federal income surtax when the Province of Employment is set to Outside Canada (48% of the calculated federal income tax). In some cases, an employer may want to disable the federal surtax withholding for a Work Assignment, or all Employees in a Business Entity with the Outside Canada Province of Employment. To achieve this, the Federal Surtax Exempt Tax Property can be created to enable. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/tax_properties \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "owner_id": "", "type": "ca::federal_oc_surtax_exempt", "value": true, "effective_from": "2026-01-01" }' ``` *Note: the value for the `ca::federal_oc_surtax_exempt` Tax Property can only be set to `true`. If this Tax Property is not created, Nmbr will withhold federal surtax by default for Employees with a Province of Employment of Outside Canada.* Similarly, when Outside Canada is set as the Province of Work, Nmbr will not calculate any provincial vacation pay, statutory holiday pay, or WCB remittances. *** ## Deprecated Province of Employment Configuration Previously, Province of Employment was configured directly on Business Entity and Work Assignment records. However, this approach did not support date-based management and has been replaced by the Tax Property model. These approaches are now deprecated and will be removed in a future update - the Tax Property based approach must be implemented to avoid any disruption. ### Changes to the Business Entity * The Province of Employment was previously determined from the Business Entities `province`, in the address. * This property may still be used to manage the province in the address, but will no longer be used to determine the POE. * All existing Business Entities should already have auto-generated POE Tax Properties. It is recommended to verify this during migration. * To retrieve the current Province of Employment for a Business Entity, use the `current_tax_jurisdiction` attribute. ### Changes to the Work Assignments * The Province of Employment was previously configured using the `tax_jurisdiction` attribute. * **Read** and **write** access to this attribute will be **removed** in a future update. * All existing Work Assignments should already have auto-generated POE Tax Properties. It is recommended to verify this during migration. * To retrieve the current Province of Employment for a Work Assignment, use the `current_tax_jurisdiction` attribute. *** ## Further Reading * CRA guidance on [determining the Province of Employment](https://www.canada.ca/en/revenue-agency/services/tax/businesses/topics/payroll/set-up-new-employee/determine-province-employment.html) # Set up Pay Rates and Recurring Earnings Source: https://docs.nmbr.co/guides/payroll-fundamentals/setup-pay-rates Paying out earnings to employees is one of the primary functions of payroll software. Depending on the province or territory of employment, different labour laws apply relating to minimum wage and vacation earnings. Some common types of earnings include: * Salary or Wage * Bonuses * Commissions * Vacation Pay * Severance Pay * Overtime ## Pay Rates and Recurring Earnings Nmbr has two features that can automatically create earning line items on payrolls: 1. Pay Rates 2. Recurring Earnings ("Other Earnings" in the Nmbr component) The biggest difference between the two is that **Pay Rates do math and Recurring Earnings don't**. Pay Rates create an earning line item whose amount may be prorated or based on the number of hours entered in each pay period. Recurring Earnings create an earning line item with a fixed amount on every payroll they're effective on. A smaller difference is that **Pay Rates and Recurring Earnings support different earning types**. Pay Rates only support salary and hourly earning types, while Recurring Earnings support all earning types *except for* salary. Otherwise, the two features are interchangeable. We recommend using Pay Rates for most employment earnings (salaries and hourly wages) and Recurring Earnings for other types of earnings (e.g. parental top-ups, commissions, etc). ## Pay Rates Having one or more Pay Rates on a Work Assignment simplifies the task of managing earnings for an Employee. Nmbr uses the Pay Rates to automatically add Earning Line Items to the next Payroll. ### Annual Salary For Pay Rates with a `type` of `salary`, the Earning Line Item will have the earning `amount` set based on the Pay Schedules frequency - e.g for a semi-monthly Pay Schedule, the Pay Rate `rate` will be divided evenly across 24 payrolls. If the Pay Rate begins in the middle of a Payroll's earning period, that Payroll will be prorated for that period, based on the working days the Pay Rate covers. If you wish to override the `amount` on a specific Salary Earning Line Item, you should set the `custom_amount` field on the Line Item. ### Hourly Wage For Pay Rates with a `type` of `hourly`, the Earning Line Item will be created with an empty `amount`. Nmbr will automatically calculate the correct `amount` once the `hours` field has been set on that Line Item. The `amount` is calculated using the Pay Rate for that Line Item. `expected_hours_per_week` is required when you create a Pay Rate of either `type`, but Nmbr only uses it for `salary` rates. On a `salary` rate it sets the default hours on the earning line item and derives the equivalent hourly rate used for proration and Overtime Rates. On an `hourly` rate it has no effect: the earning `amount` is the `hours` you enter times the hourly `rate`, and it is not used as the line item's `hours`. If you wish to override the `amount` on a specific Wage Earning Line Item, you should set the `custom_amount` field on the Line Item. #### Examples You can create a Pay Rate for an employee using the pay\_rates endpoint: **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_rates \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "title": "Location Manager", "type": "salary", "rate": "60000", "expected_hours_per_week": "38", "effective_from": "2023-11-01T00:00:00.000000Z", "work_assignment_id": "01hhcy3hg60x3dq8hfj31hgyea" }' ```
View sample JSON Response ```json theme={null} { "id": "01hhcy3j61408834dmfe8bzg24", "object": "pay_rate", "data": { "title": "Location Manager", "type": "salary", "rate": 60000, "expected_hours_per_week": 38, "effective_from": "2023-11-01T00:00:00.000000Z", "effective_to": null, "created_at": "2023-12-11T17:16:58.000000Z", "updated_at": "2023-12-11T17:16:58.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_rates/01hhcy3j61408834dmfe8bzg24" } } ```
> πŸ“˜ Supporting multiple pay rates > Nmbr gives you the ability to add multiple pay rates for a single Work Assignments. Scheduling and time and attendance software can leverage this feature to ensure employees are paid for the right roles and shifts. Once a payroll has been approved, Nmbr will automatically calculate the correct periodic earnings for the next payroll based on the Pay Schedule frequency. ### Overtime Rates In many workplaces, employees may have one or more overtime rates assigned to them. You can use the Nmbr API Overtime Rates to simplify creating, managing and calculating the correct overtime earnings for Employees. Both `salary` and `wage` Pay Rates can have one or more Overtime Rates assigned to them. When creating an Overtime Rate, you only need to provide the Pay Rate and `rate_multiplier`, and Nmbr will calculate the expected `hourly_rate`. For Pay Rates with a `type` of `salary`, the hourly rate is the annual `rate` divided by 52 weeks, then divided by `expected_hours_per_week`. If you wish to override the calculated `hourly_rate`, you may set the `hourly_rate_override`. To add an Overtime to a Pay stub, create an Earning Line Item with an `earning_type` of `overtime`, and with an `overtime_rate_id`. Nmbr will then use the `hours` to calculate the correct earning `amount` for that Line Item. #### Example Creating an Overtime Rate ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/overtime_rates \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_rate_id": "01hhcy3j61408834dmfe8bzg24", "rate_multiplier": 1.5 }' ```
View sample JSON Response ```json theme={null} { "id": "01j9m00375ea5mzbzgpx6a8yqf", "object": "overtime_rate", "data": { "pay_rate": { "id": "01hhcy3j61408834dmfe8bzg24", "object": "pay_rate", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_rates/01hhcy3j61408834dmfe8bzg24" } }, "title": "1.5x", "rate_multiplier": 1.5, "hourly_rate": 43.28, "hourly_rate_override": null, "archived_at": null, "is_editable": true, "is_deletable": true, "created_at": "2024-10-07T17:21:26.000000Z", "updated_at": "2024-10-07T17:21:26.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/overtime_rates/01j9m00375ea5mzbzgpx6a8yqf" } } ```
Creating an Overtime Earning Line Item ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/earning_line_items \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_stub_id": "", "overtime_rate_id": "01j9m00375ea5mzbzgpx6a8yqf", "hours": 20, "earning_type": "overtime" }' ```
View sample JSON Response ```json theme={null} { "id": "01j9m0cb7taf2jr460dr7kfddp", "object": "earning_line_item", "data": { "pay_stub": { "id": "01j9chznfxy478d52d69eqnhd3", "object": "pay_stub", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_stubs/01j9chznfxy478d52d69eqnhd3" } }, "amount": 865.6, "is_managed": false, "managed_amount": null, "custom_amount": 865.6, "line_item_type": "earning", "earning_type": { "id": "01J9CHYSP5DJK15NBFADAH4HNT", "object": "earning_type", "data": { "type": "overtime", "label": "Overtime", "supported_payroll_types": { "regular": true, "historical": true, "off_cycle": true } }, "links": { "self": null } }, "hours": 20, "accrued_vacation_pay": null, "recurrence": { "id": "01hhcy3j61408834dmfe8bzg24", "object": "pay_rate", "links": { "self": "https://sandbox.nmbr.co/services/payroll/pay_rates/01hhcy3j61408834dmfe8bzg24" } }, "overtime_rate": { "id": "01j9m00375ea5mzbzgpx6a8yqf", "object": "overtime_rate", "links": { "self": "https://sandbox.nmbr.co/services/payroll/overtime_rates/01j9m00375ea5mzbzgpx6a8yqf" } }, "title": null, "created_at": "2024-10-07T17:28:08.000000Z", "updated_at": "2024-10-07T17:28:08.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/earning_line_items/01j9m0cb7taf2jr460dr7kfddp" } } ```
### Ending Pay Rates All recurrence types, including pay rates, have an effective window defined by their `effective_from` and `effective_to` fields. If a pay period starts in this window, a managed line item will be created on the work assignment's pay stub automatically. However, unlike other recurrence types, pay rates allow you to create custom line items that refer to the pay rate and use it to calculate the `amount` from the `hours` at that rate. The pay rate's effective window affects custom line items in 2 ways: 1. In order to create a custom line item referring to a pay rate, the pay period must start in the pay rate's effective window. If it doesn't, the request to create the line item will be rejected. 2. When a pay rate's `effective_to` field is set (i.e. when the pay rate is ended), any line items in pay periods after that date **will be deleted automatically**. #### Example An employer has an employee working as an Apprentice Electrician 3. The employee plans to take a week of vacation 6 months from now. The employer records the planned vacation by creating a vacation pay line item for 40 hours at the employee's pay rate in the payroll 6 months from now. However, 3 months from now the employee starts a new term as an Apprentice Electrician 4. The employer ends the employee's old pay rate and creates a new pay rate. When this happens, the vacation pay earning line item will be deleted, as it refers to a pay rate that is no longer effective. The employer will need to create a new vacation pay line item at the new rate. ## Recurring Earnings ("Other Earnings") Recurring Earnings simply create an earning line item with a fixed amount on every payroll they're effective on. If you create a recurring earning, the recurring earning will create an earning line item on each payroll with that fixed amount. * The line item's amount will not be prorated in any way. * The line item's amount will not be tied to its hours. If you set the hours on the line item, its amount will not be recalculated, as there is no underlying rate to recalculate it with. The hours will appear on the pay stub, however, if set. # Statutory Withholdings Source: https://docs.nmbr.co/guides/payroll-fundamentals/statutory-withholdings You pay salaries, bonuses, commissions, vacation pay or tips to your employees. You offer them certain taxable benefits, such as personal use of a vehicle or allowances. You are also required to withhold and remit payroll deductions. Employers are responsible for deducting the following four amounts: * the Canada Pension Plan contribution * the Employment Insurance premium * federal income tax * provincial and territorial income tax Employers must remit these deductions to the Canada Revenue Agency (CRA), in addition to their portion of the Canada Pension Plan and Employment Insurance contributions. You may also be required to make other payroll deductions, such as contributions to a private pension plan or union dues. However, those deductions, which are based on previously negotiated contracts and work conditions, are not remitted to the government. > πŸ“˜ Recurring deductions > Nmbr will automatically add the required deductions to new payrolls based on employment information such as earnings, province, territory, and type/industry of work. ## Additional Deductions Employees can request extra statutory withholdings in addition to standard taxes. These are typically set by completing either: * **TD1 Form (Federal)** * **TP-1015 Form (Quebec)** When completed, these forms create the corresponding tax property on the work assignment: * `ca::federal::additional_tax` * `ca::qc::additional_tax` These properties are then used to calculate the additional tax to be withheld.\ You can also create these tax properties directly through the API if you prefer to manage them programmatically. > πŸ“˜ **Insufficient Funds**\ > If an employee’s net pay cannot cover the additional withholding: > > * Both federal and Quebec amounts will be set to zero if neither can be covered. > * If only one can be covered, the **Quebec** additional tax will be set to zero and only the **Federal** additional tax will be withheld. # Tax Agency Configuration Source: https://docs.nmbr.co/guides/payroll-fundamentals/tax-agency-configuration Setting up CRA and RQ Remittance Accounts and managing Work Assignment enrollments Nmbr uses [Remittance Accounts](/api-reference/remittance-accounts/create-a-remittance-account) for managing and reporting remittances across various external entities. This includes remittances that are managed by Nmbr, as well as those that are managed outside of Nmbr but still need to be tracked for payroll processing and reporting purposes. Every Business Entity needs at least one CRA Remittance Account, and businesses with employees working in Quebec also need an RQ account. These accounts represent where statutory withholdings β€” income tax, CPP/QPP, EI/QPIP β€” are remitted on the employer's behalf. For a full breakdown of what gets remitted to each agency, see the [Deductions & Remittances](/guides/payroll-fundamentals/deductions-and-remittances) guide. This guide covers creating and configuring these accounts, how Work Assignments are enrolled into them, the option to link an RQ account to a CRA account so enrollments stay in sync, and the payroll warnings that surface when configuration is incomplete. *** ## Managing Remittance Accounts Each Business Entity can have multiple accounts for each tax agency β€” for example, a business with multiple divisions might have separate CRA accounts for each division's payroll. However, each account must have a unique `account_identifier` within the same Business Entity and provider. When creating a CRA or RQ Remittance Account, the `account_provider` field must be set to either `ca_cra` or `ca_rq`. The `category` is automatically derived from the provider β€” both CRA and RQ accounts are assigned the `ca_tax_agency` category. The `account_identifier` is optional at creation time but must be set before Payrolls can be approved. The Remittance Account is where tax-agency configuration lives: enrollments, remittance reporting, remitter type, the tax ID (via `account_identifier`), and Tax Properties like EI Premium Reduction configured for the account. ### Listing and Finding Accounts Creating a Business Entity auto-provisions Remittance Accounts for Workers' Compensation Board (WCB), territorial government, and employer health tax providers. Any CRA or RQ accounts you create are added alongside them. The list endpoint paginates, so a new CRA or RQ account may not appear on the first unfiltered page. Use `links.next` to page through results, or filter by `account_provider` or `category`. Both filters accept comma-separated values. **Request** ```bash theme={null} curl --request GET \ --url "https://sandbox.nmbr.co/services/payroll/remittance_accounts?business_entity_id=&account_provider=ca_cra" \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` ### Account Identifier Formats Each agency has a specific identifier format: * **CRA:** 9 digits + `RP` + 4 digits (e.g. `123456782RP0001`) * **RQ:** 10 digits + `RS` + 4 digits (e.g. `9876543210RS0001`) The identifier must be unique per Business Entity and provider combination. The `account_identifier` and the corresponding `ca::tax_id` (for CRA) or `ca::qc::tax_id` (for RQ) Tax Property on the Business Entity stay in sync. Writing either one creates or updates the other. ### Updating a Remittance Account The `account_provider` field cannot be changed after creation. The `account_identifier` and `category` fields become locked once the Remittance Account is no longer editable (i.e. it has been used on a non-draft payroll). You can check the `is_editable` field on the Remittance Account to determine whether these fields can be modified. The `label` field can always be updated. ### Account Metadata Some Remittance Accounts capture extra data points specific to their category, returned in the account's `metadata` field. The available fields depend on the `category`: * **Workers’ compensation** accounts can capture `last_payment_amount`, which Nmbr uses to enable automated remittance for select providers. See the [Workers Compensation Board (WCB)](/guides/canada/workers-comp-guide) guide. CRA and RQ tax-agency accounts capture no category-specific metadata, so their `metadata` is `null`. *** ## Remitter Type Every CRA and RQ Remittance Account needs a remitter type to determine when remittance payments are due and how they are reported. The CRA assigns a remitter type to each business based on its average monthly withholding amount (AMWA). The possible values are: | Value | Description | AMWA Range | | ------------------------- | ------------------------------------------------------------------------------------- | -------------------- | | `quarterly` | Quarterly remitter β€” new small employers or accounts with a perfect compliance record | $0 – $2,999.99 | | `regular` | Regular remitter β€” remittances due by the 15th of the following month | $0 – $24,999.99 | | `accelerated_threshold_1` | Accelerated remitter (Threshold 1) β€” remittances due twice monthly | $25,000 – $99,999.99 | | `accelerated_threshold_2` | Accelerated remitter (Threshold 2) β€” remittances due within 3 business days | \$100,000+ | ### Setting the Remitter Type The remitter type can be set in two places: 1. **On the Business Entity** β€” applies as a default to all CRA and RQ Remittance Accounts under that Business Entity. 2. **On the Remittance Account** β€” overrides the Business Entity default for that specific account. When processing payments, Nmbr uses the Remittance Account's `remitter_type` if set, otherwise falls back to the Business Entity's `remitter_type`. If neither is set, payroll approval will be blocked with a `remitter_type_not_provided` warning. For most businesses, setting the remitter type on the Business Entity is sufficient β€” all CRA and RQ accounts will inherit the same value. Per-account overrides are available for cases where an account needs a different remitter type. To set the remitter type on a Remittance Account, include the `remitter_type` field when [creating](/api-reference/remittance-accounts/create-a-remittance-account) or [updating](/api-reference/remittance-accounts/update-a-remittance-account) the account. *** ## Auto-Enrollment Nmbr enrolls Work Assignments into a CRA or RQ Remittance Account automatically when it can tell which account to use. For each provider, the target account is: 1. The account with `is_default` set to `true`. Only one account per provider per Business Entity can be the default. 2. The only account of that provider, when the Business Entity has exactly one and none is marked as the default. Contractors are never enrolled in Remittance Accounts. ### CRA Auto-Enrollment When a CRA Remittance Account becomes the auto-enrollment target, every employee Work Assignment in the Business Entity that has no CRA enrollment yet is enrolled. New Work Assignments are enrolled into it as they are created. ### RQ Auto-Enrollment RQ auto-enrollment follows the same logic but only applies to Work Assignments with a **Quebec province of employment**, either set explicitly on the Work Assignment or inherited from the Business Entity. ### When Auto-Enrollment Does Not Apply Auto-enrollment is skipped when a Business Entity has more than one account for the same provider and none of them is the default. Enroll Work Assignments using the enrollment endpoints described below. A linked account is never an auto-enrollment target. Its enrollments are generated from the CRA account it follows. See [Linked Remittance Accounts](#linked-remittance-accounts). *** ## Managing Enrollments Manual enrollment is required when a Business Entity has multiple accounts for the same provider and none of them is the default β€” for example, two CRA Remittance Accounts for different divisions. ### Creating an Enrollment Use [Remittance Account Enrollments](/api-reference/remittance-account-enrollments/create-a-remittance-account-enrollment) to enroll a Work Assignment into a Remittance Account. Each enrollment has an `effective_from` date and an optional `effective_to`. The Remittance Account and Work Assignment must belong to the same Business Entity, and only `ca_cra` and `ca_rq` accounts support enrollments. Enrollments for the same Work Assignment and provider cannot overlap. If a conflict exists, pass `overlap_strategy: "replace_existing"` to automatically resolve overlaps instead of returning a validation error. Existing enrollments that started before the new `effective_from` are ended (their `effective_to` is set to the day before), and overlapping enrollments that start on or after the new `effective_from` are deleted. An account that is linked to a CRA account does not accept enrollments created this way. Its enrollments are generated from the CRA account's enrollments. See [Linked Remittance Accounts](#linked-remittance-accounts). ### Bulk Creating Enrollments Use [Bulk Operations](/api/bulk-and-batch-operations/bulk-and-batch-operations) to enroll multiple Work Assignments at once. Rather than specifying individual Work Assignments, you provide a `business_entity_id` and use the `work_assignments` field to query which ones to enroll β€” for example, all Work Assignments, or only those on a specific Pay Schedule. All selected Work Assignments receive the same Remittance Account and effective dates. *** ## Linked Remittance Accounts A business that remits to both agencies may want the same pool of employees enrolled in each. Without a link, that pool is maintained twice: every employee enrolled in the CRA account `123456782RP0001` has to be enrolled in the RQ account `9876543210RS0001` as well, with the same effective dates, and the two lists drift apart as people join and leave. Linking keeps them in step. An RQ Remittance Account can be linked to a CRA Remittance Account in the same Business Entity. Once linked, its enrollments are generated from the CRA account's enrollments and kept in sync, so there is nothing to enroll by hand. A new employee enrolled in the CRA account is enrolled in the linked account at the same time. Accounts with no link are unaffected. Linking is not the same as RQ auto-enrollment. Auto-enrollment reaches a narrower set of Work Assignments, and stops tracking the CRA account once the enrollment exists: * Auto-enrollment only covers Work Assignments with a Quebec province of employment. A linked account follows every CRA enrollment on the Business Entity's employees, whatever their province of employment. * Auto-enrollment only applies when the RQ account is the auto-enrollment target for the Business Entity. Linking works when the Business Entity has several RQ accounts. * Auto-enrollment creates the enrollment once and leaves it alone. A managed enrollment mirrors the CRA enrollment's effective dates and follows them when they change. ### Configuring a Link Set `linked_remittance_account_id` on the RQ account to the id of the CRA account it should follow. Send it when [creating](/api-reference/remittance-accounts/create-a-remittance-account) or [updating](/api-reference/remittance-accounts/update-a-remittance-account) the account. **Request** ```bash theme={null} curl --request PUT \ --url "https://sandbox.nmbr.co/services/payroll/remittance_accounts/" \ --header 'Authorization: Bearer ' \ --header 'content-type: application/json' \ --header 'accept: application/json' \ --data '{ "linked_remittance_account_id": "" }' ``` The account's `linked_remittance_account` field returns the CRA account it follows, and `null` when it follows none. Add `?expand=linked_remittance_account` to get the full account inline. A link is rejected when: * The account being linked is not an RQ account, or the account it points at is not a CRA account. * The two accounts belong to different Business Entities. * The RQ account points at itself. * Another RQ account is already linked to that CRA account. * The RQ account has `is_default` set to `true`. A linked account is never an auto-enrollment target, so it cannot also be the default. ### Managed Enrollments An enrollment generated by a link is **managed**. It always carries the same `effective_from` and `effective_to` as the CRA enrollment it came from, and follows that enrollment when the dates change. Its dates are never trimmed to fit around an existing RQ enrollment. The conflicting enrollment is end-dated or removed instead. Enrollment resources report their managed state: * `is_managed` is `true` when the enrollment was generated from a CRA enrollment. * `managing_enrollment` returns the CRA enrollment it came from, and `null` otherwise. Add `?expand=managing_enrollment` to get the full enrollment inline. * `is_editable` and `is_deletable` are both `false` while the enrollment is managed. A linked account's enrollments cannot be created, edited, or deleted directly. Passing `overlap_strategy: "replace_existing"` does not get around this. That request is rejected rather than allowed to replace a managed enrollment. To change a managed enrollment, change the CRA enrollment it came from: creating, end-dating, or deleting a CRA enrollment applies the same change on every linked account. ### Linking an Account That Already Has Enrollments Configuring a link backfills the linked account. Every employee Work Assignment already enrolled in the CRA account gets a managed enrollment on the linked account with matching effective dates. Existing RQ enrollments for those Work Assignments are resolved the same way `overlap_strategy: "replace_existing"` resolves an overlap, whichever RQ account they sit on. An enrollment that starts on or after the CRA enrollment is removed, and one that starts earlier is end-dated to the day before. An enrollment whose dates do not overlap any CRA enrollment is left alone. Nmbr recalculates the affected Work Assignments' upcoming draft payrolls so the new enrollments are reflected before approval. ### Removing a Link Set `linked_remittance_account_id` to `null`. The enrollments the link generated stay in place with their dates and account intact, and become editable and deletable again. They no longer follow the CRA account. ### Deleting Linked Accounts A CRA account with accounts linked to it cannot be deleted. Remove the links first. Deleting the RQ account is allowed, and removes its managed enrollments with it. *** ## Payroll Warnings Nmbr surfaces warnings on payrolls when Remittance Account configuration is incomplete. These warnings **block payroll approval** until resolved. ### Missing Enrollment The warnings `missing_cra_remittance_account_enrollment` and `missing_rq_remittance_account_enrollment` appear when a Pay Stub has no active enrollment for the pay period. This typically means the Work Assignment was never enrolled, or the enrollment's effective dates don't cover the payroll period. To resolve, create an enrollment for the affected Work Assignment. If the Business Entity has only one account of that provider type, the enrollment may have been inadvertently removed. ### Missing Identifier The warnings `missing_cra_remittance_account_identifier` and `missing_rq_remittance_account_identifier` appear when a Remittance Account used on the payroll has no `account_identifier` set. To resolve, [update the Remittance Account](/api-reference/remittance-accounts/update-a-remittance-account) with the correct identifier. # Tax Properties Source: https://docs.nmbr.co/guides/payroll-fundamentals/tax-properties Managing Business Entity and Work Assignment tax properties When working with Payroll, it is important to configure Business Entities and Work Assignments to ensure accurate tax calculations. The Nmbr API uses Tax Properties to manage these configurations effectively. For example, you might set the Province of Employment for a Business Entity and later update it if the business relocates. The Nmbr API enables accurate configuration and management of such attributes through Tax Properties. *** ## Viewing Available Tax Properties Resources that support Tax Properties include an `available_tax_properties` attribute. This attribute contains a list of Tax Property keys that can be managed for the specific resource instance. For example, when retrieving a Business Entity, the `available_tax_properties` attribute lists Template keys that can be used to create Tax Properties for the Business Entity. ### Request ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/business_entities/be_01jb24442merpk8byaxjpvk1j7 \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ ``` ### Response ```json theme={null} { "id": "be_01jb24442merpk8byaxjpvk1j7", "object": "business_entity", "data": { "business_number": "123456782RP0001", "name": "Consulting Corp.", "available_tax_properties": [ "ca::province_of_employment", "ca::tax_id", "ca::bc::eht" ], "created_at": "2024-10-25T15:17:20.000000Z", "updated_at": "2024-10-25T15:17:20.000000Z" }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/business_entities/be_01jb24442merpk8byaxjpvk1j7" } } ``` To configure a Tax Property, retrieve its template using the `/tax_property_templates` endpoint. The response provides detailed information about the template, including: * `label`: A user-friendly display name for the Tax Property. * `format`: The expected data format for the value (e.g., `string`, `boolean`, `numeric`, `date`). * `options`: If the Tax Property accepts only specific values, they will be listed as key-value pairs. * `allow_concurrent`: Indicates whether multiple active Tax Properties can coexist for the same entity during overlapping date periods. * `nullable`: Specifies whether the value can be set to `null`. *** ### Creating a Tax Property Use the `/tax_properties` endpoint to create a new Tax Property. Required parameters include: * `owner_id`: The ULID of the resource (e.g., Business Entity or Work Assignment) associated with the Tax Property. * `type`: The template `type` value (e.g., `ca::province_of_employment`, `ca::mb::eht`). * `effective_from`: The date this Tax Property becomes effective. Tax Properties are applied based on their effective dates relative to the `pay_date` of a payroll. #### Request ```bash theme={null} curl --request GET \ --url https://sandbox.nmbr.co/services/payroll/tax_property_templates/ca::province_of_employment \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ ```
View JSON Response ```json theme={null} { "id": "ca::province_of_employment", "object": "tax_property_template", "data": { "type": "ca::province_of_employment", "label": "Province Of Employment", "format": "string", "options": { "ca_ab": "Alberta", "ca_bc": "British Columbia", "ca_mb": "Manitoba", "ca_nb": "New Brunswick", "ca_nl": "Newfoundland and Labrador", "ca_ns": "Nova Scotia", "ca_nt": "Northwest Territories", "ca_nu": "Nunavut", "ca_on": "Ontario", "ca_pe": "Prince Edward Island", "ca_qc": "Quebec", "ca_sk": "Saskatchewan", "ca_yt": "Yukon" }, "allow_concurrent": false, "feature": "onboarding", "nullable": false }, "links": { "self": "https://sandbox.nmbr.co/services/payroll/tax_property_templates/ca::province_of_employment" } } ```
*** ## Managing Tax Properties Tax Properties are essential for calculating accurate taxes, contributions, and withholdings for employees and employers. They follow these rules: * Locked after payroll approval: Tax Properties cannot be updated or deleted once a payroll that uses the property is marked as `approved`. * Editable attributes: The `is_editable` attribute determines if a Tax Property can be modified. If `false`, only the `effective_to` date can be updated. Each Tax Property inherits its `allow_concurrent` attribute from its template: * If `allow_concurrent` is `true`, you can create multiple Tax Properties for the same entity that overlap by date. * If `allow_concurrent` is `false`, you must delete or end the existing Tax Property before creating a new one. The new `effective_from` date must be after the previous Tax Property's `effective_to` date. *** ## Ending a Tax Property To end the effectiveness of a Tax Property, set its `effective_to` date. This determines the last date the property will apply to payroll tax calculations. The Tax Property remains active for all relevant payrolls with a `pay_date` between the `effective_from` and `effective_to` dates, inclusive. When setting the `effective_to` date, it must not be earlier than the `earliest_valid_effective_to`, which is determined by how the property has been used: * The `effective_from` date, if the Tax Property has never been used in an approved payroll. * The `pay_date` of the most recent payroll that used it. > πŸ“˜ Pay Dates and Tax Properties > A Tax Property cannot be ended before the `pay_date` of the most recent payroll that used it. This is because tax calculations are based on the **date the employee is paid**, not when the work was performed. *** ## Tax Property Priority Some Tax Properties may be set at both the Business Entity and Work Assignment levels. Priority rules determine which value is applied: * Generally, Work Assignment Tax Properties take precedence over Business Entity Tax Properties when both are active for a given Payroll Pay Date. #### Example If the `ca::province_of_employment` Tax Property is set for both a Business Entity and a Work Assignment, the Work Assignment value is used to calculate provincial taxes for the employee. # TD1 Forms Source: https://docs.nmbr.co/guides/payroll-fundamentals/td1-forms Collect federal and provincial TD1 tax credit amounts for accurate withholding A TD1, formally the Canada Revenue Agency (CRA) Personal Tax Credits Return, is the form an employer collects from an employee to figure out how much income tax to withhold from each pay. The amounts an employee claims on it lower the tax deducted from their pay, so the employer sends the right amount to the CRA. TD1s are not filed with the CRA, and the employee doesn't use them for their own return. They exist so the employer can calculate withholding and record the employee's TD1 code. Employees complete a federal TD1 and the TD1 for their province. Both are collected when the employee starts a job and at the beginning of each calendar year, and again whenever they: * Want to increase the tax deducted from their pay. * Want to claim additional deductions. * Have a significant life change, such as going back to school or taking on a dependent. If an employee doesn't submit their TD1s, the employer withholds tax using the CRA's default (basic personal) amount for the year. An employee with two jobs may claim their tax credits on only one job's TD1. ## TD1 forms in the Nmbr API TD1s are forms. Read the [Forms guide](/guides/payroll-fundamentals/forms) for how to list form types, read their fields, create a form, and update it. This page covers what's specific to TD1s. Nmbr provides every federal and provincial TD1 as its own form type: * `td1`: the federal TD1. * `td1on`, `td1ab`, `td1bc`, and so on: one form type per province and territory. * `td1x`: Statement of Commission Income and Expenses, for commission employees. * `tp_1015_3_v`: the QuΓ©bec Source Deductions Return, QuΓ©bec's equivalent of the TD1. A few things set TD1s apart from other forms: * **Their owner is a work assignment.** A TD1 attaches to one work assignment, not to the employee as a whole, so an employee with two jobs can claim different amounts on each. Use a `wrkas_` ID as the `owner_id` when you create one. * **They're records, not filings.** TD1s aren't submitted to a government agency, generated from payroll data, or exported. You create one, set the claim amounts, and Nmbr uses them in withholding calculations. Retrieve a TD1's fields from the [Retrieve a form type](/api-reference/form-types/retrieve-a-form-type) endpoint before you build against it. The claim amounts are `currency` fields keyed by line, such as `line_1_basic_personal_amount`. ## Creating a TD1 Create a TD1 with the [Create a form](/api-reference/forms/create-a-form) endpoint. Send the `type`, the work assignment as `owner_id`, and any claim amounts. **Request** ```json theme={null} # POST /services/payroll/forms { "type": "td1on", "owner_id": "wrkas_01HX3F7T8B2D", "line_1_basic_personal_amount": 12747.0 } ``` The response is the full form, with any unset lines returned as `null`. Update it later with the [Update a form](/api-reference/forms/update-a-form) endpoint, sending only the lines you want to change. # Terminations & Rehires Source: https://docs.nmbr.co/guides/payroll-fundamentals/terminations Managing employee terminations and rehires through the Nmbr API After completing your offboarding process in your HRIS or employee management platform, there are a few steps to take in order to complete your offboarding in Nmbr: 1. Update the `effective_to` date on the employee's recurring items (Pay Rates, Earnings, Allowances, Benefits, Deductions, Reimbursements) to stop payment. 2. Add severance to the employee's pay stub, including any unpaid vacation time. 3. Issue a Record of Employment (ROE). 4. Archive the Work Assignment and/or Employee to remove them from future payrolls. Nmbr does not keep track of termination and rehire information outside of Records of Employment (ROE). This is typically a task for your HRIS or employee management system. ## Termination ### Ending Recurring Items In order to stop paying an employee, you will need to set an `effective_to` date on all active recurring items attached to the Work Assignment. This includes Pay Rates, Earnings, Allowances, Employee Benefits, Employer Benefits, Deductions, and Reimbursements. You can set this date in the future in order to align with the last day of the employee's employment. **End a Pay Rate** ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/pay_rates/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "effective_to": "2025-03-01" }' ``` Repeat this for each active recurring item (Earnings, Allowances, Benefits, Deductions, Reimbursements) attached to the Work Assignment. You can also use the [terminate endpoint](/api-reference/work-assignments/terminate-a-work-assignment) to set the `effective_to` date on all active recurring items in a single request. This sets the same `effective_to` date across all Pay Rates, Earnings, Allowances, Benefits, Reimbursements, and Deductions for the Work Assignment. **Using the Terminate Endpoint** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/work_assignment//terminate \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "effective_date": "2025-03-01", "archived_at": "2025-03-02" }' ``` The optional `archived_at` parameter lets you archive the Work Assignment in the same request. ### Adding Severance Pay The Canada Labour Code outlines requirements for severance pay. In order to accommodate many different types of severance payments, Nmbr allows you to add these as regular earnings to your employee's pay stub. **Request** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/earnings \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_stub_id": "01h3mfbb506cgb0yje5bmn9f6k", "earning_type": "severance", "amount": 1000 }' ``` ### Issue a Record of Employment A Record of Employment (ROE) provides information on employment history. It is the single most important document used by employees to apply for Employment Insurance (EI) benefits. Service Canada uses the information on the ROE to determine whether a person is eligible to receive EI benefits, what the benefit amount will be, for how long the benefits will be paid and to ensure that no one misuses EI funds or receives benefits in error. As an employer, you are required to issue an ROE each time one of your employees experiences an interruption of earnings. See the [Record of Employment](/guides/canada/record-of-employment) guide for more details. ### Archiving Once an employee's final payroll has been processed, archive the Work Assignment and optionally the Employee record to remove them from active lists and future payrolls. **Archive a Work Assignment** Set the `archived_at` attribute on the Work Assignment to the day after the employee's final pay period. This prevents the Work Assignment from generating pay stubs on future payrolls. ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/work_assignments/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "archived_at": "2025-03-02" }' ``` **Archive an Employee** Set the `archived_at` attribute on the Employee to remove them from the default employee list. You can still query the employee directly by ID. ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/employees/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "archived_at": "2025-03-02" }' ``` *** ## Rehiring When rehiring a previously terminated employee, the process is essentially the reverse of termination. There is no dedicated rehire endpoint -- instead, you compose the rehire from individual API calls to unarchive, reactivate, or create new recurring items. The key steps are: 1. Unarchive the Employee (if archived). 2. Unarchive the Work Assignment to resume generating pay stubs. 3. Reactivate or create new Pay Rates, Earnings, Allowances, Benefits, Deductions, and Reimbursements. ### Step 1: Unarchive the Employee If the Employee was archived at termination, clear the `archived_at` field to make them visible in employee lists again. ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/employees/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "archived_at": null }' ``` ### Step 2: Unarchive the Work Assignment Set `archived_at` to `null` on the Work Assignment. This triggers Nmbr to automatically generate draft pay stubs for all upcoming payroll periods on the associated Pay Schedule. ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/work_assignments/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "archived_at": null }' ``` Once the Work Assignment is unarchived, Nmbr will automatically create draft pay stubs for future payroll periods. However, these pay stubs will be empty until you reactivate or create recurring items (Pay Rates, Benefits, etc.) for the Work Assignment. ### Step 3: Reactivate or Create Recurring Items You have two approaches for restoring an employee's pay configuration after a rehire. Choose the approach that best fits your data architecture and product requirements. #### Option A: Reinstate Existing Items Remove the `effective_to` date from the items that were ended at termination. This reactivates the original records so they apply to future payrolls. ```bash theme={null} curl --request PUT \ --url https://sandbox.nmbr.co/services/payroll/pay_rates/ \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "effective_to": null }' ``` Repeat for each recurring item (Earnings, Allowances, Benefits, Deductions, Reimbursements) that should be reactivated. Reinstating existing items removes the historical `effective_to` date, which means the item will appear as if it was never ended. This may not accurately reflect the employee's actual employment history. If maintaining a clear timeline of each employment period is important to your integration, consider creating new items instead. #### Option B: Create New Items Create new recurring items with a fresh `effective_from` date set to the rehire date. This preserves a clear timeline where each employment period has its own set of items with distinct `effective_from` and `effective_to` ranges. **Create a new Pay Rate** ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/pay_rates \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "", "type": "salary", "rate": 75000, "effective_from": "2025-06-01" }' ``` This approach gives you a clean audit trail: | Period | Item | effective\_from | effective\_to | | ---------------- | ----------------- | --------------- | ------------- | | First employment | Pay Rate (Salary) | 2024-01-01 | 2025-03-01 | | Rehire | Pay Rate (Salary) | 2025-06-01 | *null* | Repeat for each type of recurring item the employee should have upon rehire -- Earnings, Allowances, Employee Benefits, Employer Benefits, Deductions, and Reimbursements. If the employee's compensation or benefits have changed since their termination, Option B is the natural choice since you'll be setting up the new terms from scratch. ### Summary | Step | Action | Endpoint | Key Field | | ---- | ------------------------- | -------------------------------------------- | ------------------------------- | | 1 | Unarchive Employee | `PUT /employees/` | `archived_at: null` | | 2 | Unarchive Work Assignment | `PUT /work_assignments/` | `archived_at: null` | | 3a | Reinstate existing items | `PUT /pay_rates/` (etc.) | `effective_to: null` | | 3b | Create new items | `POST /pay_rates` (etc.) | `effective_from: ` | Remember that an Employee may only have **one active Work Assignment per Pay Schedule**. If the employee is returning to the same Pay Schedule, you must unarchive the existing Work Assignment rather than creating a new one. # Vacation Pay Source: https://docs.nmbr.co/guides/payroll-fundamentals/vacation-pay Employees are entitled to receive a minimum vacation pay of either four percent or six percent of their gross wages earned during the 12-month vacation entitlement year or stub period, excluding any previously paid vacation pay. This ensures compliance with employment standards legislation and guarantees fair compensation for accrued vacation time. You can configure the vacation pay percentage and accrual settings per Work Assignment. ## Setting Vacation Pay Percentage To set the vacation pay percentage for a Work Assignment, you can use the `vacation_pay_settings` endpoint. This entity will allow you to set the percentage, method of vacation pay, and the effective dates for a specific Work Assignment. * Each Work Assignment may have only one active Vacation Pay Setting at a time. * The previously active setting must be ended before creating a new one. * Once a setting has been used to calculate vacation pay, it cannot be deleted. * The API provides the `earliest_valid_effective_to` attribute to simplify setting the `effective_to` date. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/vacation_pay_settings \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "work_assignment_id": "", "percentage": 4, "effective_from": "2026-01-01", "vacation_pay_method": "manual" }' ```
View sample JSON Response ```json theme={null} { "id": "vapay_01JM383AXX0V98G4HN6HWAX9YB", "object": "vacation_pay_setting", "data": { "percentage": 4, "vacation_pay_method": "manual", "effective_from": "2026-01-01", "earliest_valid_effective_to": "2026-01-01", "effective_to": null, "is_editable": true, "is_deletable": true, "work_assignment": { "id": "wrkas_01JM383AXGZRCT6VGP5A4TDMWT", "object": "work_assignment", "links": { "self": "/work_assignments/wrkas_01JM383AXGZRCT6VGP5A4TDMWT" } }, "note": "Vacation Pay", "created_at": "2026-01-01T00:00:00.000000Z", "updated_at": "2026-01-01T00:00:00.000000Z" }, "links": { "self": "/vacation_pay_settings/vapay_01JM383AXX0V98G4HN6HWAX9YB" } } ```
Once the vacation pay percentage is set, all applicable Earning, Allowance, and Reimbursement Line Items for that Work Assignment will being accruing vacation pay. The accrual can be seen on the Line Item in the `accrued_vacation_pay` attribute. Vacation Pay is accrued on a Line Item if that Earning, Allowance, or Reimbursement Type has vacation applied in the current Province of Employment of the Work Assignment. Nmbr follows the applicable employment standards to determine if vacation pay should be accrued. ## Paying Out Vacation Pay Accrued vacation pay can be paid out two different ways, `manual` or `per_period`. The default method is `manual`, if one is not specified. ### Manual Vacation Pay To pay earned vacation pay manually at a time of your choosing, you can select the Vacation Pay earning type when generating a new earning. You should also include the number of hours taken to ensure reporting and records of employment are accurate. ```bash theme={null} curl --request POST \ --url https://sandbox.nmbr.co/services/payroll/earning_line_items \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "pay_stub_id": "axzjqzC5oOZ51h3mqmXK", "earning_type": "vacation_pay", "custom_amount" : 4.00, "hours": 1 }' ``` ### Per-Period Vacation Pay If you prefer that Vacation Pay is paid out automatically for each pay period, you can do so by setting the vacation pay method to `per_period` when creating the Vacation Pay Setting. The generated vacation pay items can be reviewed and modified before running payroll. Employees' total vacation pay accrual as well as vacation pay that has been paid out in a given period will be displayed on their pay stubs. ## Vacation Pay Setting Selection The Nmbr payroll engine needs to pick one Vacation Pay Setting to apply to each Payroll. Each Vacation Pay Setting has an effective date range (`effective_from` to `effective_to`). The Nmbr payroll engine uses the `vacation_pay_formula_setting` attribute on the Business Entity to decide which of the Payroll's dates must fall in the Vacation Pay Settings' effective date ranges in order to select that Vacation Pay Setting for the Payroll: * `pay_date` (default) - select the Vacation Pay Setting whose effective range contains the Payroll's `pay_date`. * `period_start` - select the Vacation Pay Setting whose effective range contains the Payroll's `period_start`. * `period_end` - select the Vacation Pay Setting whose effective range contains the Payroll's `period_end`. ### Example A Work Assignment has two Vacation Pay Settings: | Setting | `effective_from` | `effective_to` | | -------------- | ---------------- | -------------- | | Setting A (4%) | 2026-01-01 | 2026-06-30 | | Setting B (6%) | 2026-07-01 | *(open)* | A Payroll has `period_start = 2026-06-20`, `period_end = 2026-07-03`, and `pay_date = 2026-07-10`. The selected setting depends on the Business Entity's `vacation_pay_formula_setting`: * `pay_date`: **Setting B** will be used, because the Payroll's `pay_date` (2026-07-10) falls in B's range * `period_start`: **Setting A** will be used, because the Payroll's `period_start` (2026-06-20) falls in A's range * `period_end`: **Setting B** will be used, because the Payroll's `period_end` (2026-07-03) falls in B's range # Usage Source: https://docs.nmbr.co/guides/usage-billing/usage Query usage records and summaries for billing Usage data helps partners reconcile payroll activity to billing. Nmbr exposes usage in two levels of detail: * `usage_records`: the individual billable events Nmbr recorded. * `usage_summaries`: monthly rollups of those records by company and event type. Use usage summaries when you need invoice totals. Use usage records when you need to explain or reconcile a specific count. ## How usage is counted Usage summaries are based on when a usage record was recorded, not on the payroll period the payroll represents. For payroll-related usage, this means the count lands in the month when the payroll activity is processed and recorded by Nmbr. If you process historical or backdated payrolls in May, the resulting usage records are counted in May, even if those payrolls represent work from March or April. Example: * On May 7, you process an April payroll for 15 employees. * Nmbr records the paid employee usage on May 7. * The `employee_paid` count appears in the May usage summary. * It does not appear in the April usage summary. This timing rule is the same reason usage records include `recorded_at`: if a summary count looks unexpected, inspect the underlying records and compare their `recorded_at` timestamps. ## Usage event types Each usage summary has an `event` and a `count`. These are the usage event types Nmbr currently returns: | Event | What it counts | | ------------------------ | --------------------------------------------------------------- | | `employee_paid` | Employee pay stubs paid during the usage month. | | `contractor_paid` | Contractor pay stubs paid during the usage month. | | `employee_paid_unique` | Unique employees paid during the usage month. | | `contractor_paid_unique` | Unique contractors paid during the usage month. | | `funding_failure` | Billable funding failures recorded during the usage month. | | `payroll_expedited` | Expedited payrolls paid during the usage month. | | `kyb_attempt` | Business verification attempts recorded during the usage month. | | `business_launched` | Businesses that launched during the usage month. | Partners billed per employee per pay run usually reconcile against `employee_paid` and `contractor_paid`. Partners billed per employee per month usually reconcile against `employee_paid_unique` and `contractor_paid_unique`. ## Get monthly usage summaries Use `GET /usage_summaries` to retrieve monthly rollups. Usage endpoints are partner-level endpoints, so authenticate with your partner secret. ```bash theme={null} curl --request GET \ --url "https://sandbox.nmbr.co/services/payroll/usage_summaries?company_id=cmp_123&period_start=2025-05-01&period_end=2025-05-31" \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "object": "list", "data": [ { "id": "usum_123", "object": "usage_summary", "data": { "company": { "id": "cmp_123", "object": "company", "links": { "self": "/companies/cmp_123" } }, "event": "employee_paid", "count": 15, "period_start": "2025-05-01", "period_end": "2025-05-31", "created_at": "2025-05-07T20:11:32.000000Z", "updated_at": "2025-05-07T20:11:32.000000Z" }, "links": { "self": "/usage_summaries/usum_123" } }, { "id": "usum_456", "object": "usage_summary", "data": { "company": { "id": "cmp_123", "object": "company", "links": { "self": "/companies/cmp_123" } }, "event": "contractor_paid_unique", "count": 8, "period_start": "2025-05-01", "period_end": "2025-05-31", "created_at": "2025-05-07T20:11:32.000000Z", "updated_at": "2025-05-07T20:11:32.000000Z" }, "links": { "self": "/usage_summaries/usum_456" } } ] } ``` Nmbr creates one summary row per company, month, and event type. Events with no usage may still appear with a count of `0`. ## Reconcile a summary with usage records Use `GET /usage_records` to inspect the records that feed a summary. Filter by the same company and the recorded date range for the month you are reconciling. ```bash theme={null} curl --request GET \ --url "https://sandbox.nmbr.co/services/payroll/usage_records?company_id=cmp_123&recorded_at%5Bgte%5D=2025-05-01&recorded_at%5Blt%5D=2025-06-01" \ --header 'Authorization: Bearer ' \ --header 'accept: application/json' ``` **Response** ```json theme={null} { "object": "list", "data": [ { "id": "urec_123", "object": "usage_record", "data": { "company": { "id": "cmp_123", "object": "company", "links": { "self": "/companies/cmp_123" } }, "event": "employee_paid", "record": { "id": "pay_stub_123", "object": "pay_stub", "links": { "self": "/pay_stubs/pay_stub_123" } }, "recorded_at": "2025-05-07 20:11:32", "created_at": "2025-05-07T20:11:32.000000Z", "updated_at": "2025-05-07T20:11:32.000000Z" }, "links": { "self": "/usage_records/urec_123" } } ] } ``` If a payroll was processed in May for an April pay period, the usage record still has a May `recorded_at` timestamp and contributes to the May summary. ## Practical reconciliation flow 1. Fetch `GET /usage_summaries` for the company and month you want to invoice. 2. Group the returned rows by `event`. 3. Use `employee_paid` plus `contractor_paid` for per-pay-run billing. 4. Use `employee_paid_unique` plus `contractor_paid_unique` for per-month billing. 5. If a count is unexpected, fetch `GET /usage_records` for the same company and recorded month, then inspect the `event`, `record`, and `recorded_at` values. # Configuring Email Source: https://docs.nmbr.co/portal/configuring-email Learn how to configure Nmbr to send emails on your behalf. Nmbr can send payroll-related emails on your behalf, including pay stub notifications and payroll deadline reminders. To set up email sending, log into the Nmbr Portal and navigate to the 'Email' section under 'Configure' in the sidebar. ![image info](https://raw.githubusercontent.com/nmbrco/api-docs-public/main/resources/email_configuration.png) ## Email Sending Configuration ### Email Provider Before you begin, you will need an email provider. Currently, [Mailgun](https://www.mailgun.com/), [Mandrill](https://www.mandrillapp.com/) and [SendGrid](https://sendgrid.com/) are supported. You will need to create an account with the provider. Once you have an account with an email provider, select it from the dropdown menu. ### Primary Language Nmbr can send emails in English or French. ### From Name and Address These fields define the sender's name and email address. For example, a company named "Success People Systems" might use "SPS Payroll" as the sender name and "[payroll@successpeoplesystems.com](mailto:payroll@successpeoplesystems.com)" as the email address. Recipients will see: `"SPS Payroll "`. ## Emails ### Pay Stub Emails On the day before payday, Nmbr can email employees their pay stub. The pay stub will be sent from the email address configured in the email provider settings and delivered to the employee's `personal_email` address. If no personal email is configured, the employee's `work_email` is used instead. The pay stub is sent as a password-protected PDF attachment. The email includes instructions for unlocking the PDF, which uses digits from the employee's date of birth and social insurance number. You can also upload a company logo to be used in the email and customize the header colours to fit your brand. ### Payroll Deadline Emails Nmbr can send an email to the Business Entity's contact email reminding them of an approaching payroll approval deadline. Payroll deadline reminders are sent only if a payroll remains in draft as the deadline approaches: * **Four days before the approval deadline:** Nmbr sends a reminder email. * **Day of the deadline:** An urgent follow-up email is sent if the payroll remains unapproved. # Working With The Nmbr Portal Source: https://docs.nmbr.co/portal/working-with-the-nmbr-dashboard Learn about using the Portal to operate your payroll product ![image info](https://raw.githubusercontent.com/nmbrco/api-docs-public/main/resources/nmbr_portal.png) The Portal serves as an internal hub designed to facilitate the management of your payroll product across all customer accounts, offering enhanced visibility for you and your team. This tool provides a comprehensive overview, covering high-level elements like companies and employees on your platform, as well as delving into more detailed aspects such as individual payrolls, benefits, and deductions. Utilizing the Portal eliminates the need to construct an internal tool for data visualization. We equip your operations team and developers with essential features, enabling them to craft an exceptional experience for your customers. ![image info](https://raw.githubusercontent.com/nmbrco/api-docs-public/main/resources/paystub.png) ## What Portal offers your operations teams For operations and implementations teams, Portal exposes functionality to interact directly with Nmbr without the need for developer support. Common use cases include company implementations, payroll insights, and the ability to view and download reports at the click of a button. ![image info](https://raw.githubusercontent.com/nmbrco/api-docs-public/main/resources/request_logs.png) ## What Portal offers your developers The Portal provides developers with in-depth access to webhooks and API logs. The webhooks page grants visibility into the details on the status of every webhook delivery attempt, making setup and debugging much simpler. In addition, the API logs page surfaces information on every HTTP request made with an API key.