---
title: "How to Detect Employee Onboarding and Offboarding Events with"
img: https://s3.us-east-2.amazonaws.com/unified-article-images/how_to_detect_employee_onboarding_and_offboarding_events_with-icon.png
date: 2026-02-02T17:10:00.000Z
updated: 2026-10-21T01:07:03.441Z
readingTime: 5
tag: Product
description: "To detect new hires and leavers across HR systems with Unified.to's HR & Directory API, compare each employee's `employmentstatus`, `hiredat` and..."
url: "https://unified.to/blog/how_to_detect_employee_onboarding_and_offboarding_events_with"
---

# How to Detect Employee Onboarding and Offboarding Events with

To detect new hires and leavers across HR systems with [Unified.to](http://unified.to/)'s [HR & Directory API](/hris), compare each employee's `employment_status`, `hired_at` and `terminated_at` between reads, and use employee [webhooks](/blog/replacing_polling_with_event_driven_integrations_using_virtual_webhooks) where the integration sends them. This guide is for teams automating onboarding, offboarding and access changes. Lifecycle automation breaks when products treat onboarding and offboarding as one-time events instead of **state transitions**.


Across HR systems, employee lifecycle data is fragmented. Start dates, termination dates, employment status, and organizational attributes are updated independently and often asynchronously. Some systems emit explicit events. Others only report current state. Many require teams to reconstruct lifecycle changes by comparing snapshots or relying on vendor-specific semantics.


For product teams, this creates real operational risk:

- New hires aren't provisioned on time
- Departed employees retain access longer than intended
- Role or team changes fail to trigger downstream updates
- 'Joiners' and 'leavers' are detected inconsistently across HRISs

Many tools attempt to solve this by inventing lifecycle event objects or relying on undocumented vendor behavior. That approach is brittle and hard to audit.


[Unified.to](http://unified.to/)'s HR & Directory API doesn't invent lifecycle events. It returns **observable employee state** (employment status, start and end dates, groups and locations) and, where the integration supplies it, an `updated_at` timestamp. Lifecycle events are derived by comparing state over time, using consistent semantics across HR systems.


This guide shows how to detect joiners, leavers and other employee changes with [Unified.to](http://unified.to/)'s HR & Directory API, without vendor-specific logic or inferred history.


## What does lifecycle detection cover here?


This article focuses on **detecting and reacting to employee lifecycle changes**, not performing provisioning directly.


We will:

- Identify new employees (onboarding)
- Identify exited employees (offboarding)
- Detect changes to active employees that require updates
- Keep downstream systems current incrementally

We will not:

- Model role history or promotions
- Infer lifecycle events from payroll or benefits
- Require webhooks to function correctly
- Define provisioning logic for downstream systems

[Unified.to](http://unified.to/) provides the lifecycle signal. Your product decides how to act on it.


## Does [Unified.to](http://unified.to/) send onboarding and offboarding events?


Not as such. There's no "lifecycle event" object; on supported integrations, employee created, updated and deleted webhooks tell you a record changed, and the lifecycle meaning comes from the employee's state:

- Onboarding → employee appears with `employment_status = ACTIVE` and a `hired_at` date
- Offboarding → `employment_status` transitions or `terminated_at` is set
- Updates → any meaningful change reflected in `updated_at`

This model is intentional. It avoids vendor-specific event semantics and keeps lifecycle detection consistent across HRISs.


## Objects you'll use


### Employees (`HrisEmployee`)


Employees are the source of truth for lifecycle state.


Relevant fields:

- `id`
- `employment_status`
- `hired_at`
- `terminated_at`
- `updated_at`
- `groups[]`
- `locations[]`
- `company_id`

Important constraints:

- Lifecycle signals are represented as state, not events
- `updated_at` reflects changes to the employee record
- Not all HRISs update all fields simultaneously

### Groups (`HrisGroup`)


Groups provide organizational context.


Relevant fields:

- `id`
- `name`
- `parent_id`
- `type`
- `company_id`

Groups are useful for assigning onboarding or offboarding steps by department or team.


### Locations (`HrisLocation`)


Locations provide geographic context.


Relevant fields:

- `id`
- `name`
- `address.region`
- `address.country`
- `company_id`

Locations are often used to trigger jurisdiction-specific onboarding or exit steps.


### Companies (`HrisCompany`)


Companies define scope.


Relevant fields:

- `id`
- `name`

This allows lifecycle syncing in multi-entity organizations without assuming a single global org.


## Step 1: Perform an initial employee ingest


Start by ingesting the current employee population.


```typescript
import { UnifiedTo } from '@unified-api/typescript-sdk';

const sdk = new UnifiedTo({
  security: { jwt: process.env.UNIFIED_API_KEY! },
});

async function fetchEmployees(connectionId: string) {
  const employees = [];
  let offset = 0;
  const limit = 100;

  while (true) {
    const page = await sdk.hris.listHrisEmployees({
      connectionId,
      limit,
      offset,
      sort: 'updated_at',
      order: 'asc',
      fields: [
        'id',
        'employment_status',
        'hired_at',
        'terminated_at',
        'updated_at',
        'groups',
        'locations',
        'company_id',
      ].join(','),
    });

    if (!page || page.length === 0) break;

    employees.push(...page);
    offset += limit;
  }

  return employees;
}
```


This establishes a baseline state.


## Step 2: Detect onboarding (joiners)


A new employee is typically identified by:

- A previously unseen `id`
- An `employment_status` of `ACTIVE`
- A populated `hired_at` date

```typescript
function detectJoiners(
  previous: Map<string, any>,
  current: any[]
) {
  return current.filter(
    (e) =>
      !previous.has(e.id) &&
      e.employment_status === 'ACTIVE'
  );
}
```


These employees can trigger onboarding steps such as:

- Account creation
- Training assignment
- Welcome communications

## Step 3: Detect offboarding (leavers)


Offboarding is detected through state change.


Common signals:

- `employment_status` transitions to `INACTIVE`
- `terminated_at` becomes populated

```typescript
function detectLeavers(
  previous: Map<string, any>,
  current: any[]
) {
  return current.filter((e) => {
    const prev = previous.get(e.id);
    if (!prev) return false;

    return (
      prev.employment_status === 'ACTIVE' &&
      e.employment_status !== 'ACTIVE'
    );
  });
}
```


These records can drive:

- Access revocation
- Device or account cleanup
- Exit steps

## Step 4: Detect updates to active employees


Not all lifecycle-relevant changes are joiners or leavers.


Examples:

- Department changes
- Location changes
- Company reassignment

Where the integration returns `updated_at`, you can detect records that need re-evaluation; elsewhere, compare the fields you care about.


```typescript
function detectUpdates(
  previous: Map<string, any>,
  current: any[]
) {
  return current.filter((e) => {
    const prev = previous.get(e.id);
    if (!prev) return false;

    return e.updated_at !== prev.updated_at;
  });
}
```


These updates often require partial downstream changes rather than full onboarding or offboarding.


## Step 5: Re-read only changed employees where you can


Where an integration supports the `updated_gte` filter, such as SAP SuccessFactors, Personio, Okta and Microsoft Entra ID, you can re-read only changed employees. Elsewhere, list all employees and compare.


Typical pattern:

1. Persist last processed `updated_at`
2. Re-fetch employees with `updated_gte`
3. Compare state against stored snapshot
4. Derive joiners, leavers, and updates

## Can webhooks replace polling?


On supported integrations, yes, for detection: employee events are native on HiBob, Personio, FactorialHR, [Remote.com](http://remote.com/), Google Workspace Directory and Microsoft Entra ID (including deletes), and come from [virtual webhooks](/blog/what_are_virtual_webhooks_how_they_differ_from_sync_based_webhooks) on BambooHR, Workday, SAP SuccessFactors, UKG Pro HCM and Okta, which check at an interval you set, as often as every minute on paid plans (as of 20 October 2026). ADP Workforce Now and Deel send no employee events.


However:

- Webhooks are an optimisation, not a requirement
- Polling with `updated_at` remains the baseline approach
- Lifecycle logic should not depend on webhook guarantees

This ensures correctness even when webhooks are unavailable or delayed.


## Can I provision accounts from the same data?


Yes. Use the lifecycle signal to create or remove accounts in your own product, or write to a directory: Okta, Microsoft Entra ID, Google Workspace Directory and JumpCloud create, update and remove employees through the same API, and [Unified.to](http://unified.to/)'s [SCIM API](https://docs.unified.to/scim/overview) offers SCIM Users and Groups over its HR integrations. Device records (asset tag, model, operating system, assigned users) are readable on integrations such as Microsoft Entra ID and Google Workspace Directory (as of 19 October 2026).


To keep a current copy of employees in your own database, Database Sync (Grow, Pro and Scale) writes changes into MongoDB, MySQL, Postgres, MSSQL, MariaDB, Supabase or Snowflake for objects with native or virtual webhooks.


## What doesn't [Unified.to](http://unified.to/) assume?


[Unified.to](http://unified.to/) does not:

- Emit explicit onboarding or offboarding events
- Infer lifecycle changes from payroll or benefits
- Model role or title history
- Guarantee synchronous field updates across HRISs

It returns observable state changes and leaves lifecycle interpretation to your product.


## How do I start?


Employee lifecycle syncing is about **state awareness**, not event orchestration.


[Unified.to](http://unified.to/)'s HR & Directory API reads employee state from the source at request time (start dates, termination dates, groups, locations and change timestamps where supplied) across 679 HR & Directory integrations, so onboarding and offboarding steps follow the HR system.


With explicit state and incremental detection, lifecycle automation becomes reliable instead of reactive.


→ [Start your 30-day free trial](https://app.unified.to/login)


→ [Book a demo](https://calendly.com/d/cph9-g8n-jzg/connect-with-unified)