---
title: "How to Forecast Headcount and Hiring Needs with"
img: https://s3.us-east-2.amazonaws.com/unified-article-images/how_to_forecast_headcount_and_hiring_needs_with-icon.png
date: 2026-02-02T17:10:00.000Z
updated: 2026-10-21T01:10:23.924Z
readingTime: 5
tag: Product
description: "To forecast headcount with Unified.to, build a baseline from HRIS data (who is employed now, when people joined and left, and where they sit) and add open..."
url: "https://unified.to/blog/how_to_forecast_headcount_and_hiring_needs_with"
---

# How to Forecast Headcount and Hiring Needs with

To forecast headcount with [Unified.to](http://unified.to/), build a baseline from HRIS data (who is employed now, when people joined and left, and where they sit) and add open roles and applications from the ATS for hiring demand. [Unified.to](http://unified.to/)'s [HR & Directory API](/hris) returns employment status, hire and termination dates, groups, locations and company on supported integrations; its [ATS API](/ats) returns jobs and applications. This guide is for FP&A, workforce-planning and HR analytics teams; the forecasting model stays yours.


Across HR systems, workforce size is modeled inconsistently. Some platforms treat contractors as employees. Others exclude interns or seasonal workers. Employment start dates, termination timing, and organizational attribution vary widely. In many systems, past changes have to be reconstructed from payroll or provisioning data.


For a PM or FP&A team, this creates immediate risk:

- Who counts as headcount today?
- When did growth or attrition actually occur?
- Are changes tied to departments, locations, or companies consistently?
- Can forecasts be explained and defended when numbers are questioned?

Many products attempt to solve this by inventing 'employment history' models or extrapolating from adjacent data like payroll or benefits. That works until customers audit the numbers or compare results across HR systems.


[Unified.to](http://unified.to/)'s HR & Directory API doesn't predict hiring or infer changes. It returns what the HRIS records (employment status, start and end dates, and group, location and company links) in one schema, read from the HRIS at request time.


This guide shows how to build a defensible headcount baseline and hiring trend analysis on top of that model. The output isn't a prediction engine. It's a clean, auditable foundation that forecasting tools depend on.


## What does this guide cover, and what doesn't it?


This article focuses on **enabling** forecasting, not performing it.


We will:

- Establish current headcount accurately
- Measure observed changes over time (hires and exits)
- Segment headcount by department, location, and employment type

We will not:

- Predict future hires automatically
- Infer compensation or capacity
- Reconstruct undocumented employment history

Those decisions belong in your planning models, not the integration layer.


## How do you count headcount at a point in time?


An employee counts if they were hired on or before that date and not terminated before it.


Headcount is not a static count of records. It is a **time-bound property** of employees.


At any point in time, an employee is either:

- Employed
- Not employed

Changes occur at discrete moments:

- Hiring (`hired_at`)
- Termination (`terminated_at`)
- Status transitions (`employment_status`)

[Unified.to](http://unified.to/) returns those dates where the HRIS records them (`hired_at` and `terminated_at` on supported integrations). Build on them rather than guessing.


## Objects you'll use


### Employees (`HrisEmployee`)


Employees are the source of truth for headcount state and change.


Relevant fields:

- `id`
- `employment_status`
- `employment_type`
- `hired_at`
- `terminated_at`
- `updated_at`
- `groups[]`
- `locations[]`
- `company_id`
- `termination_reason` (some integrations): to separate voluntary from involuntary exits

Important constraints:

- Compensation is not required for headcount.
- Payroll artifacts are not used to infer employment.
- `updated_at` reflects changes to the employee record, not necessarily employment events.

### Groups (`HrisGroup`)


Groups define organizational attribution.


Relevant fields:

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

Groups enable rollups by department, division, or business unit. Their semantics are customer-defined and should not be hardcoded.


### Locations (`HrisLocation`)


Locations define geographic attribution.


Relevant fields:

- `id`
- `name`
- `address` (region, country)
- `is_active`
- `company_id`

Locations support regional planning and geo-based hiring analysis.


### Companies (`HrisCompany`)


Companies define scope.


Relevant fields:

- `id`
- `name`

This allows headcount planning across subsidiaries or legal entities without assuming a single global org.


## Step 1: Fetch employees incrementally


Employee lists are paginated; `updated_gte` incremental reads work on supported integrations (not Workday, BambooHR or HiBob, as of 19 October 2026).


```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 out = [];
  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',
        'employment_type',
        'hired_at',
        'terminated_at',
        'updated_at',
        'groups',
        'locations',
        'company_id',
      ].join(','),
    });

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

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

  return out;
}
```


This is sufficient for both current state and change detection.


## Step 2: Define 'current headcount'


Headcount definitions vary by product. Unified leaves this policy to you.


A common baseline:

- `employment_status === 'ACTIVE'`
- `terminated_at` is null

```typescript
function currentHeadcount(employees: any[]) {
  return employees.filter(
    (e) => e.employment_status === 'ACTIVE' && !e.terminated_at
  );
}
```


You may choose to:

- Exclude contractors
- Include interns
- Handle seasonal workers differently

Those rules are explicit and configurable, using `employment_type` (FULL_TIME, PART_TIME, CONTRACTOR, INTERN, CONSULTANT, CASUAL and others) on integrations that return it.


## Step 3: Segment headcount by org and location


Once you have the current population, segmentation is a join problem.


Examples:

- Headcount by department: `employee.groups[].id`
- Headcount by location: `employee.locations[].id`
- Headcount by company: `employee.company_id`
- Headcount by employment type: `employee.employment_type`

Groups and locations share one schema across integrations, so the same rollup code works wherever the HRIS returns them.


## Step 4: Observe hiring and attrition over time


Observed change is derived from dates, not inferred history.


### Hires


```typescript
function hiresBetween(employees: any[], start: Date, end: Date) {
  return employees.filter((e) => {
    if (!e.hired_at) return false;
    const hired = new Date(e.hired_at);
    return hired >= start && hired <= end;
  });
}
```


### Terminations


```typescript
function terminationsBetween(employees: any[], start: Date, end: Date) {
  return employees.filter((e) => {
    if (!e.terminated_at) return false;
    const terminated = new Date(e.terminated_at);
    return terminated >= start && terminated <= end;
  });
}
```


These counts can be grouped by department, location, or company using the same joins as current headcount.


## Step 4b: How do you add hiring demand from the ATS?


Headcount shows the past; open roles show the plan. [Unified.to](http://unified.to/)'s ATS API lists jobs (with `status` and, on integrations such as Greenhouse, `number_of_openings`) and applications across 162 applicant tracking systems such as Greenhouse and Lever, so you can count open roles and pipeline per department next to current headcount. A few HR integrations also return positions directly (the HR Job object, on ELMO and Workday (Legacy) as of 19 October 2026). See [ATS API Integration](https://unified.to/blog/ats_api_integration_real_time_recruiting_data_candidate_pipelines_and_hiring_automation).


## Step 5: How do you keep the baseline current?


On supported integrations, use employee change events (native or [virtual webhooks](/blog/what_are_virtual_webhooks_how_they_differ_from_sync_based_webhooks)) or `updated_gte` incremental reads. A typical loop:

1. Initial full load
2. Persist `updated_at` watermark
3. Re-fetch with `updated_gte`
4. Recompute affected aggregates only

Your dashboard is then as current as your webhook interval or read schedule, without rebuilding the dataset.


## What does [Unified.to](http://unified.to/) leave to your model?


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

- Predict future hires
- Infer employment from payroll or benefits
- Reconstruct undocumented job history
- Normalize customer-specific policies

This keeps headcount analysis explainable and auditable.


## How this supports forecasting


With a correct baseline and observed trends, your product can:

- Model growth scenarios
- Compare hiring velocity across teams
- Plan regional expansion
- Benchmark attrition rates

The forecasting logic lives in your application; [Unified.to](http://unified.to/) supplies the HR and ATS records it runs on.


## Next steps


Pick your headcount definition, confirm `hired_at`, `terminated_at` and `groups` coverage on your customers' integrations, then add ATS jobs. Related: [How to Analyze Employee Population for Compliance and Risk](https://unified.to/blog/how_to_analyze_employee_population_for_compliance_and_risk_grc_with_unified_hr_and_directory_api) · [HR API Integration](https://unified.to/blog/hr_api_integration_real_time_employee_data_directories_and_workforce_automation).


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


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