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

# HRIS Integration

> Sync employee data from your HR system using Merge.dev

## Overview

Xenia integrates with 50+ HRIS (Human Resource Information System) providers through [Merge.dev](https://merge.dev), enabling automatic employee synchronization, role assignment, and location mapping.

**Supported Providers:**

* BambooHR, Rippling, Workday, ADP
* Gusto, Paylocity, Paycom, Paychex
* UKG, Ceridian, Namely, Zenefits
* And 40+ more HRIS platforms

**Key Capabilities:**

* One-time and continuous employee sync
* Automatic role assignment via job title mapping
* Multi-location assignment (1:M mapping)
* Review-based or automatic employee onboarding
* Real-time sync via webhooks

```mermaid theme={null}
sequenceDiagram
    participant Admin as Workspace Admin
    participant API as Xenia API
    participant Merge as Merge.dev
    participant HRIS as HRIS Provider

    Admin->>API: 1. Request link token
    API->>Merge: Get Merge Link token
    Merge-->>API: Link token
    API-->>Admin: Link token

    Admin->>Merge: 2. Complete Merge Link UI
    Merge->>HRIS: Authenticate
    HRIS-->>Merge: Access granted
    Merge-->>Admin: Public token

    Admin->>API: 3. Complete connection
    API->>Merge: Exchange token
    Merge-->>API: Account token
    API-->>Admin: Connection active

    Merge->>API: 4. Webhook: sync_completed
    API->>API: Process employee data
    API-->>Admin: Employees available
```

***

## Prerequisites

Before using HRIS integration:

1. **Feature Flag**: `HRIS` must be enabled for your workspace
2. **Permissions**: User must have HRIS management permissions
3. **Role Setup**: Define roles in Xenia for job title mapping

***

## Connection Management

### Get Link Token

Generate a Merge.dev link token to initiate the connection flow.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/users/hris/merge/link-token" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "endUserEmail": "admin@company.com",
      "endUserOrganization": "Company Name",
      "categories": ["hris"]
    }'
  ```
</CodeGroup>

**Request Body:**

| Field                 | Type   | Required | Description                                   |
| --------------------- | ------ | -------- | --------------------------------------------- |
| `endUserEmail`        | string | No       | Admin email for Merge notifications           |
| `endUserOrganization` | string | No       | Organization name displayed in Merge Link     |
| `endUserOriginId`     | string | No       | Custom identifier for the connection          |
| `integrationSlug`     | string | No       | Pre-select a specific HRIS (e.g., `bamboohr`) |
| `categories`          | array  | No       | Filter integrations (default: `["hris"]`)     |

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "linkToken": "link_token_xxx",
    "integrationName": null,
    "expiresAt": "2024-12-24T10:00:00Z"
  }
}
```

### Complete Connection

After the user completes the Merge Link UI, exchange the public token for a permanent connection.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/users/hris/merge/complete" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "publicToken": "pt_xxx_from_merge_link",
      "integrationSlug": "bamboohr",
      "integrationName": "BambooHR"
    }'
  ```
</CodeGroup>

**Request Body:**

| Field             | Type   | Required | Description                             |
| ----------------- | ------ | -------- | --------------------------------------- |
| `publicToken`     | string | Yes      | Token received from Merge Link callback |
| `integrationSlug` | string | No       | HRIS provider identifier                |
| `integrationName` | string | No       | Display name for the integration        |
| `linkedAccountId` | string | No       | Merge's linked account ID               |
| `categories`      | array  | No       | Integration categories                  |
| `metadata`        | object | No       | Custom metadata to store                |

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "message": "Successfully connected to BambooHR",
  "data": {
    "id": "account-uuid",
    "accountId": "account-uuid",
    "integrationSlug": "bamboohr",
    "integrationName": "BambooHR",
    "provider": "merge",
    "status": "active",
    "categories": ["hris"],
    "linkedAccountId": "merge-linked-account-id",
    "connectedAt": "2024-12-23T10:00:00Z",
    "workspaceId": "workspace-uuid"
  }
}
```

### List Connections

Retrieve all HRIS connections for a workspace with sync status.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris/connections" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": [
    {
      "id": "account-uuid",
      "provider": "Merge.dev",
      "integrationSlug": "bamboohr",
      "integrationName": "BambooHR",
      "categories": ["hris"],
      "status": "active",
      "syncState": "synced",
      "hasCompletedInitialSync": true,
      "lastSyncedAt": "2024-12-23T08:00:00Z",
      "lastSyncStatus": "success",
      "syncError": null,
      "employeeCount": 150,
      "syncProgress": {
        "recordsProcessed": 150,
        "recordsSucceeded": 148,
        "recordsFailed": 2,
        "employeesCreated": 10,
        "employeesUpdated": 138
      },
      "createdAt": "2024-12-01T10:00:00Z",
      "updatedAt": "2024-12-23T08:00:00Z"
    }
  ]
}
```

**Sync States:**

| State                      | Description                                    |
| -------------------------- | ---------------------------------------------- |
| `waiting_for_initial_sync` | Connection established, waiting for first sync |
| `initial_sync_in_progress` | First sync running                             |
| `syncing`                  | Incremental sync in progress                   |
| `synced`                   | All data synchronized                          |
| `error`                    | Sync failed (check `syncError`)                |
| `unlinked`                 | Connection disconnected                        |

### Disconnect Connection

Unlink an HRIS connection. This preserves user data but stops sync.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://api.xenia.team/api/v1/mgt/hris/connections/{accountId}" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "message": "Successfully disconnected from BambooHR. Users and employee data have been preserved.",
  "data": {
    "id": "account-uuid",
    "integration": "BambooHR",
    "disconnectedAt": "2024-12-23T10:00:00Z",
    "deletedMirrors": 5,
    "deletedTokens": 1
  }
}
```

***

## Employee Management

### List Stored Employees

Retrieve HRIS employees stored in Xenia with advanced filtering.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris/employees?page=1&pageSize=25&employmentStatus=ACTIVE&includeCompany=true" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Query Parameters:**

| Parameter          | Type         | Default     | Description                                |
| ------------------ | ------------ | ----------- | ------------------------------------------ |
| `page`             | number       | 1           | Page number                                |
| `pageSize`         | number       | 25          | Items per page (max: 200)                  |
| `search`           | string       | -           | Search name, email, employee number        |
| `employmentStatus` | string/array | -           | Filter: `ACTIVE`, `INACTIVE`, `TERMINATED` |
| `accountId`        | string       | -           | Filter by HRIS account                     |
| `homeLocationId`   | string       | -           | Filter by home location                    |
| `workLocationId`   | string       | -           | Filter by work location                    |
| `includeCompany`   | boolean      | true        | Include company details                    |
| `includeLocations` | boolean      | true        | Include location details                   |
| `includeManager`   | boolean      | false       | Include manager details                    |
| `includeDeleted`   | boolean      | false       | Include soft-deleted records               |
| `sortBy`           | string       | `createdAt` | Sort field                                 |
| `sortOrder`        | string       | `DESC`      | Sort direction: `ASC` or `DESC`            |

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "employees": [
      {
        "id": "employee-uuid",
        "WorkspaceId": "workspace-uuid",
        "HRISAccountId": "account-uuid",
        "remoteId": "hris-employee-id",
        "firstName": "John",
        "lastName": "Doe",
        "preferredName": "Johnny",
        "displayFullName": "John Doe",
        "workEmail": "john.doe@company.com",
        "personalEmail": "john@personal.com",
        "employeeNumber": "EMP001",
        "employmentStatus": "ACTIVE",
        "startDate": "2023-01-15",
        "endDate": null,
        "remoteCreatedAt": "2023-01-10T00:00:00Z",
        "remoteModifiedAt": "2024-12-20T00:00:00Z",
        "Company": {
          "id": "company-uuid",
          "legalName": "Company Inc.",
          "displayName": "Company"
        },
        "HomeLocation": {
          "id": "location-uuid",
          "name": "Headquarters",
          "remoteId": "hris-location-id"
        },
        "xeniaStatus": {
          "isXeniaUser": true,
          "status": "ACTIVE",
          "statusLabel": "Active User",
          "userId": "user-uuid",
          "workspaceUserId": "workspace-user-uuid",
          "inviteStatus": "Active",
          "canInvite": false,
          "isLinkedToHRIS": true,
          "hrisEmployeeId": "employee-uuid"
        }
      }
    ],
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "total": 150,
      "totalPages": 6,
      "hasMore": true
    }
  }
}
```

**Xenia Status Values:**

| Status             | Description                      |
| ------------------ | -------------------------------- |
| `NO_EMAIL`         | Employee has no work email       |
| `NOT_INVITED`      | Eligible for invitation          |
| `NOT_IN_WORKSPACE` | User exists but not in workspace |
| `DELETED`          | User was deleted                 |
| `ACTIVE`           | Active Xenia user                |
| `PENDING_INVITE`   | Invitation sent, not accepted    |
| `INACTIVE`         | User deactivated                 |

### Bulk Invite Employees

Queue bulk invitations for HRIS employees to Xenia.

<CodeGroup>
  ```bash cURL theme={null}
  # Simple mode - same role for all
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/accounts/{accountId}/employees/bulk-invite" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "employeeIds": ["emp-uuid-1", "emp-uuid-2", "emp-uuid-3"],
      "roleId": "default-role-uuid"
    }'
  ```
</CodeGroup>

<CodeGroup>
  ```bash cURL (Advanced Mode) theme={null}
  # Advanced mode - per-employee configuration
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/accounts/{accountId}/employees/bulk-invite" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "employees": [
        {
          "employeeId": "emp-uuid-1",
          "roleId": "manager-role-uuid",
          "locationId": "hq-location-uuid"
        },
        {
          "employeeId": "emp-uuid-2",
          "roleId": "staff-role-uuid",
          "locationId": "branch-location-uuid"
        }
      ]
    }'
  ```
</CodeGroup>

**Request Body (Simple Mode):**

| Field             | Type   | Required | Description                              |
| ----------------- | ------ | -------- | ---------------------------------------- |
| `employeeIds`     | array  | Yes\*    | Employee UUIDs to invite (max: 3000)     |
| `roleId`          | string | No       | Default role for all employees           |
| `locationMapping` | object | No       | HRIS location ID → Xenia location ID map |

**Request Body (Advanced Mode):**

| Field                    | Type   | Required | Description                              |
| ------------------------ | ------ | -------- | ---------------------------------------- |
| `employees`              | array  | Yes\*    | Per-employee configuration (max: 3000)   |
| `employees[].employeeId` | string | Yes      | Employee UUID                            |
| `employees[].roleId`     | string | No       | Role for this employee                   |
| `employees[].locationId` | string | No       | Location for this employee               |
| `locationMapping`        | object | No       | HRIS location ID → Xenia location ID map |

<Note>
  Use either `employeeIds` OR `employees`, not both. They are mutually exclusive.
</Note>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "message": "Bulk invite job queued. 45 employee(s) will be invited.",
  "data": {
    "jobId": "bull-job-id",
    "total": 50,
    "eligible": 45,
    "skipped": [
      {
        "employeeId": "emp-uuid-4",
        "email": null,
        "name": "Jane Smith",
        "reason": "NO_WORK_EMAIL"
      },
      {
        "employeeId": "emp-uuid-5",
        "email": "inactive@company.com",
        "name": "Bob Johnson",
        "reason": "EMPLOYMENT_STATUS_INACTIVE"
      }
    ]
  }
}
```

***

## Job Title Mapping

Map HRIS job titles to Xenia roles for automatic role assignment during invite.

### List Job Titles

Get unique job titles from synced employees with mapping status.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/job-titles?accountId={accountId}&sortBy=employeeCount&sortOrder=DESC" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": [
    {
      "jobTitle": "Software Engineer",
      "employeeCount": 25,
      "isMapped": true,
      "mappedToRole": {
        "roleId": "developer-role-uuid",
        "roleTitle": "Developer"
      }
    },
    {
      "jobTitle": "Store Manager",
      "employeeCount": 12,
      "isMapped": false,
      "mappedToRole": null
    }
  ],
  "meta": {
    "total": 15,
    "page": 1,
    "pageSize": 50,
    "totalPages": 1
  }
}
```

### List Job Title Mappings

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/job-title-mappings?accountId={accountId}" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

### Create/Upsert Job Title Mappings

Create or update job title mappings in bulk.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/job-title-mappings" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "accountId": "account-uuid",
      "create": [
        {
          "hrisJobTitle": "Software Engineer",
          "roleId": "developer-role-uuid"
        },
        {
          "hrisJobTitle": "Store Manager",
          "roleId": "manager-role-uuid"
        }
      ],
      "delete": ["old-mapping-uuid-1"]
    }'
  ```
</CodeGroup>

**Request Body:**

| Field                   | Type   | Required | Description               |
| ----------------------- | ------ | -------- | ------------------------- |
| `accountId`             | string | Yes      | HRIS account UUID         |
| `create`                | array  | No       | Mappings to create/update |
| `create[].hrisJobTitle` | string | Yes      | Job title from HRIS       |
| `create[].roleId`       | string | Yes      | Xenia role UUID           |
| `delete`                | array  | No       | Mapping UUIDs to delete   |

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "created": [
      {
        "id": "mapping-uuid-1",
        "hrisJobTitle": "Software Engineer",
        "roleId": "developer-role-uuid",
        "roleTitle": "Developer",
        "isActive": true,
        "createdAt": "2024-12-23T10:00:00Z"
      }
    ],
    "updated": [
      {
        "id": "mapping-uuid-2",
        "hrisJobTitle": "Store Manager",
        "roleId": "manager-role-uuid",
        "roleTitle": "Manager",
        "isActive": true,
        "updatedAt": "2024-12-23T10:00:00Z"
      }
    ],
    "deleted": [
      {
        "id": "old-mapping-uuid-1",
        "deleted": true
      }
    ],
    "errors": []
  }
}
```

***

## Location Mapping

Map HRIS locations to Xenia locations. Supports 1:M mapping (one HRIS location to multiple Xenia locations).

### List HRIS Locations

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/locations?accountId={accountId}" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "locations": [
      {
        "id": "hris-location-uuid",
        "WorkspaceId": "workspace-uuid",
        "HRISAccountId": "account-uuid",
        "remoteId": "bamboo-location-123",
        "name": "Downtown Office",
        "phoneNumber": "+1-555-0100",
        "street1": "123 Main St",
        "city": "New York",
        "state": "NY",
        "zipCode": "10001",
        "country": "US",
        "locationType": "office"
      }
    ],
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "total": 8,
      "totalPages": 1
    }
  }
}
```

### Create/Upsert Location Mappings

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/location-mappings" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "accountId": "account-uuid",
      "create": [
        {
          "hrisLocationId": "hris-location-uuid",
          "locationId": "xenia-location-uuid-1",
          "isPrimary": true
        },
        {
          "hrisLocationId": "hris-location-uuid",
          "locationId": "xenia-location-uuid-2",
          "isPrimary": false
        }
      ]
    }'
  ```
</CodeGroup>

**Request Body:**

| Field                     | Type    | Required | Description                              |
| ------------------------- | ------- | -------- | ---------------------------------------- |
| `accountId`               | string  | Yes      | HRIS account UUID                        |
| `create`                  | array   | No       | Mappings to create/update                |
| `create[].hrisLocationId` | string  | Yes      | HRIS location UUID                       |
| `create[].locationId`     | string  | Yes      | Xenia location UUID                      |
| `create[].isPrimary`      | boolean | No       | Set as primary location (default: false) |
| `delete`                  | array   | No       | Mapping UUIDs to delete                  |

<Note>
  **1:M Mapping**: One HRIS location can map to multiple Xenia locations. When an employee is invited, they'll be assigned to ALL mapped locations, with `defaultLocationId` set from the primary mapping.
</Note>

***

## Auto-Sync Configuration

Configure automatic employee synchronization behavior.

### Get Auto-Sync Settings

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/settings" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "id": "settings-uuid",
    "WorkspaceId": "workspace-uuid",
    "HRISAccountId": "account-uuid",
    "autoSyncEnabled": true,
    "autoInviteEnabled": true,
    "autoDeactivateEnabled": true,
    "inviteMode": "review_required",
    "defaultRoleId": "basic-user-role-uuid",
    "defaultLocationId": "hq-location-uuid",
    "notifyAdmins": true,
    "notifyOnNewHires": true,
    "notifyOnTerminations": true,
    "DefaultRole": {
      "id": "basic-user-role-uuid",
      "title": "Basic User"
    },
    "DefaultLocation": {
      "id": "hq-location-uuid",
      "name": "Headquarters"
    }
  }
}
```

### Update Auto-Sync Settings

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/settings" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "autoSyncEnabled": true,
      "autoInviteEnabled": true,
      "autoDeactivateEnabled": true,
      "inviteMode": "review_required",
      "defaultRoleId": "basic-user-role-uuid",
      "defaultLocationId": "hq-location-uuid",
      "notifyAdmins": true,
      "notifyOnNewHires": true,
      "notifyOnTerminations": true
    }'
  ```
</CodeGroup>

**Request Body:**

| Field                   | Type    | Description                          |
| ----------------------- | ------- | ------------------------------------ |
| `autoSyncEnabled`       | boolean | Enable automatic data sync           |
| `autoInviteEnabled`     | boolean | Automatically invite new employees   |
| `autoDeactivateEnabled` | boolean | Auto-deactivate terminated employees |
| `inviteMode`            | string  | `automatic` or `review_required`     |
| `defaultRoleId`         | string  | Default role for new employees       |
| `defaultLocationId`     | string  | Default location for new employees   |
| `notifyAdmins`          | boolean | Send admin notifications             |
| `notifyOnNewHires`      | boolean | Notify on new hire detection         |
| `notifyOnTerminations`  | boolean | Notify on termination detection      |

### Trigger Manual Sync

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/trigger-sync" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "message": "Sync job queued successfully",
    "jobId": "bull-queue-job-id"
  }
}
```

***

## Employee Review Workflow

When `inviteMode` is set to `review_required`, new employees are queued for admin review.

### List Pending Employees

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/pending-employees?changeType=new_hire" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

**Query Parameters:**

| Parameter    | Type   | Description                                            |
| ------------ | ------ | ------------------------------------------------------ |
| `changeType` | string | Filter: `new_hire`, `update`, `termination`, `re_hire` |
| `page`       | number | Page number (default: 1)                               |
| `pageSize`   | number | Items per page (default: 50)                           |

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "mirrors": [
      {
        "id": "mirror-uuid",
        "HRISAccountId": "account-uuid",
        "HRISEmployeeId": "employee-uuid",
        "status": "pending_review",
        "changeType": "new_hire",
        "matchConfidence": "high",
        "MatchedUserId": null,
        "HRISEmployee": {
          "id": "employee-uuid",
          "remoteId": "hris-123",
          "firstName": "John",
          "lastName": "Doe",
          "workEmail": "john.doe@company.com"
        },
        "MatchedUser": null,
        "createdAt": "2024-12-23T08:00:00Z"
      }
    ],
    "pagination": {
      "page": 1,
      "pageSize": 50,
      "total": 5,
      "totalPages": 1
    }
  }
}
```

**Change Types:**

| Type          | Description                                |
| ------------- | ------------------------------------------ |
| `new_hire`    | New employee detected in HRIS              |
| `update`      | Employee data changed                      |
| `termination` | Employee marked as terminated              |
| `re_hire`     | Previously terminated employee reactivated |

### Approve Employees

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/approve-employees" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "mirrorIds": ["mirror-uuid-1", "mirror-uuid-2"]
    }'
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "status": true,
  "code": 200,
  "data": {
    "approved": 2,
    "processing": {
      "queued": 2,
      "deactivated": 0,
      "errors": 0
    }
  }
}
```

### Reject Employees

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/reject-employees" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}" \
    -H "Content-Type: application/json" \
    -d '{
      "mirrorIds": ["mirror-uuid-3"],
      "rejectionReason": "Contractor - not eligible for Xenia access"
    }'
  ```
</CodeGroup>

### View Sync History

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/employee-history?status=completed&page=1" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

### View Webhook Logs

For debugging sync issues, view Merge.dev webhook events.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.xenia.team/api/v1/mgt/hris-integration/auto-sync/accounts/{accountId}/webhook-logs?processingStatus=failed" \
    -H "x-client-key: YOUR_CLIENT_KEY" \
    -H "x-client-secret: YOUR_CLIENT_SECRET" \
    -H "workspace-id: {workspaceId}"
  ```
</CodeGroup>

***

## Permissions Reference

| Permission                       | Description                                     |
| -------------------------------- | ----------------------------------------------- |
| `CAN_ACCESS_HRIS`                | Base access to HRIS features (required for all) |
| `CAN_VIEW_HRIS_INTEGRATION`      | Read-only access to connections and employees   |
| `CAN_MANAGE_HRIS_INTEGRATION`    | Full management of HRIS connections             |
| `CAN_MANAGE_HRIS_EMPLOYEES`      | Approve/reject employees, bulk invite           |
| `CAN_MANAGE_HRIS_LOCATIONS`      | Manage location mappings                        |
| `CAN_MANAGE_HRIS_ROLES`          | Manage job title mappings                       |
| `CAN_MANAGE_HRIS_CONFIGURATIONS` | Configure auto-sync settings                    |

***

## Common Workflows

### Initial HRIS Setup

```mermaid theme={null}
flowchart TD
    A[Get Link Token] --> B[User completes Merge Link]
    B --> C[Complete Connection]
    C --> D[Wait for Initial Sync]
    D --> E{Sync Complete?}
    E -->|Yes| F[Configure Mappings]
    F --> G[Set Auto-Sync Settings]
    G --> H[Bulk Invite Employees]
```

### Employee Onboarding Flow

```mermaid theme={null}
flowchart TD
    A[HRIS Webhook: New Employee] --> B{Invite Mode?}
    B -->|Automatic| C[Create User & Send Invite]
    B -->|Review Required| D[Add to Pending Queue]
    D --> E[Admin Reviews]
    E -->|Approve| C
    E -->|Reject| F[Mark Rejected]
    C --> G[Apply Role from Mapping]
    G --> H[Assign to Mapped Locations]
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Configure mappings before bulk invite">
    Set up job title → role mappings and location mappings before inviting employees. This ensures automatic role and location assignment.
  </Accordion>

  <Accordion title="Use review mode for initial sync">
    Start with `inviteMode: "review_required"` to manually verify the first batch of employees before switching to automatic mode.
  </Accordion>

  <Accordion title="Monitor sync status regularly">
    Check connection status and webhook logs periodically to catch sync issues early. Set up admin notifications for failures.
  </Accordion>

  <Accordion title="Handle terminated employees">
    Enable `autoDeactivateEnabled` to automatically deactivate users when they're terminated in the HRIS. This maintains security without manual intervention.
  </Accordion>

  <Accordion title="Use 1:M location mapping strategically">
    When an employee works across multiple Xenia locations, map their HRIS location to all relevant Xenia locations with one marked as primary.
  </Accordion>
</AccordionGroup>

***

## Related Guides

* [User Lifecycle](/guides/workflows/user-lifecycle) - Manual user management
* [Role Management](/guides/workflows/role-management) - Create roles for mapping
* [Location Hierarchy](/guides/workflows/location-hierarchy) - Set up locations
