---
title: "Bulk Upsert Employee Enrollments"
method: POST
path: "/api/v1/time-tracking/employees/bulk-upsert"
tags: ["Time Tracking", "Public API"]
---

# Bulk Upsert Employee Enrollments

`POST /api/v1/time-tracking/employees/bulk-upsert`

## Request

- Base URL: `https://companySubDomain.bamboohr.com`
- URL: `https://companySubDomain.bamboohr.com/api/v1/time-tracking/employees/bulk-upsert`
- Auth: one of:
  - HTTP basic
  - OAuth 2
    - Authorization code: `/authorize.php`
    - Token URL: `/token.php` scopes: `time_tracking:employees.write`
- TypeScript: <https://skmtc.dev/bamboohr/apis/bamboohr-api/docs/api/v1/time-tracking/employees/bulk-upsert/post.ts> (a function with typed inputs; its response is checked against the schema)

Bulk enables, disables, or reassigns employee enrollments. The body is a top-level JSON array of between 1 and 1000 upsert records; each record requires `employeeId` and applies the same merge-patch semantics as the single-employee PATCH. Request-level validation (payload shape, record cap, missing `employeeId`) runs synchronously; the records themselves are applied asynchronously, so the response is 202 with a `requestId` for log correlation rather than the resulting enrollments. Confirm the final state by reading the enrollments back through `GET /api/v1/time-tracking/employees`. Per-record processing errors, such as an unknown `employeeId` or `configurationId`, do not surface in the response. Send `atomic=true` to commit the whole batch as one unit instead, in which case any per-record failure aborts the batch and returns 422 with nothing applied.

OAuth Scopes: time_tracking:employees.write

## Query parameters

- `atomic` boolean

## Headers

- `Idempotency-Key` string

## Request body

- TimeTrackingBulkUpsertEmployeeTimeTrackingDataRecordV1[]
  - `employeeId` integer, required: The employee the record applies to.
  - `enabled` boolean: True to enable time tracking for the employee, false to disable it. Disabling retains the enrollment record for history.
  - `configurationId` integer, nullable: The configuration to enroll the employee in. Null falls back to the company's GLOBAL configuration. Cannot be sent in the same record that sets enabled to false.
  - `enabledOn` string, date: Effective date for the enable, in YYYY-MM-DD format. Only honored while enabled is being set to true; defaults to today.

## Response `202`

The batch has been accepted.

- TimeTrackingBulkUpsertEmployeeTimeTrackingDataAcceptedV1: Acknowledgement that a bulk employee enrollment upsert has been accepted.
  - `requestId` string, required: Correlation id for the accepted batch. Returned for log correlation only; there is no status polling endpoint.
  - `message` string, required: How to confirm the final enrollment state.

## Other responses

- `400`: Malformed request body (not an array, or a record that does not name an employee).
- `401`: Unauthorized. Missing or invalid authentication.
- `403`: Forbidden. Insufficient permissions.
- `409`: Conflict. The Idempotency-Key was reused with a different request, either a different body or a different `atomic` mode.
- `422`: Validation error (an empty batch, more than the maximum number of records, an unusable record field, an invalid `atomic` value, or, in atomic mode, any per-record failure).

## Changes

- **2026-11-03** `922fc15f43a7`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/bamboohr/apis/bamboohr-api/changes/api/v1/time-tracking/employees/bulk-upsert/post.md)

---

[API](https://skmtc.dev/bamboohr/apis/bamboohr-api.md) - [All operations](https://skmtc.dev/bamboohr/apis/bamboohr-api/llms.txt) - [OpenAPI document](https://skmtc.dev/bamboohr/apis/bamboohr-api/revisions/922fc15f43a7?raw)
