How-to
HRIS sync basics
A directory knows who has an account. An HR system knows who works at the company — including the person who starts on Monday and the one whose last day is in three weeks. When your product needs employment context rather than login context, that difference is the whole reason to integrate.
When you actually need it
Most products do not. If all you need is accurate accounts and clean deprovisioning, a directory integration is simpler, faster to configure and already in place at your customer.
HR data earns its place when your product reasons about employment: org charts and reporting lines, cost centre or department attribution, headcount-based entitlements, or anything that has to be correct on somebody's first day rather than on their first sign-in.
| You need | Best source | Why |
|---|---|---|
| Accounts that exist and are removed | Directory (SCIM) | Faster, universal, and what IT already runs |
| Manager and reporting line | HR system | Directories carry this inconsistently or not at all |
| Department or cost centre | HR system | Usually authoritative only in HR |
| Start and termination dates | HR system | Directories know about now, not about next Monday |
| Employment type or status | HR system | Contractor versus employee is an HR concept |
| Login identity | Directory | HR systems are not identity providers |
How the sync behaves
HR integrations are usually scheduled rather than event-driven. Where SCIM pushes a change within seconds, an HR connector reads on a cycle — often hourly — because the underlying systems are built around batch processing and payroll runs.
Plan for that. A product that promises instant reflection of an HR change will be wrong most of the time, and the delay is not something your integration can remove.
1{2 "id": "employee_01HQZX8N4T",3 "organizationId": "org_01HQZX8N4T",4 "externalId": "E-10482",5 "firstName": "Avery",6 "lastName": "Lindqvist",7 "workEmail": "avery@foo-corp.example",8 "jobTitle": "Staff Engineer",9 "department": "Platform",10 "managerId": "employee_01HQZX8N51",11 "employmentType": "full_time",12 "startDate": "2024-09-02",13 "terminationDate": null,14 "status": "active"15}
Reconciling two sources
Once you have both a directory and an HR feed, the same person arrives twice with different identifiers. Deciding which source owns which field, in advance and in writing, is the difference between a useful integration and a field that flips back and forth on every sync.
- Match on work email first, then fall back to employee ID if the customer populates it in both systems. Expect a residue that matches on neither.
- Give unmatched records a place to live rather than dropping them. An HR record with no directory account is normal for a new starter; a directory account with no HR record is normal for a service account.
- Assign field ownership explicitly: the directory owns login identity, the HR system owns employment attributes, and neither owns what your product invented.
- Never let an HR sync deactivate a login. Terminations should raise a task or a flag, not silently cut access on a date that may be wrong.
That last point is not caution for its own sake. Termination dates are edited, reversed and back-dated in HR systems far more often than directory records are, and an automated cut based on one has locked people out of their own accounts on their working days.
Future-dated changes
HR systems record intent: somebody starts on the second, transfers on the fifteenth, leaves at the end of the month. These records exist before they take effect, and a naive sync applies them immediately.
Store the effective date rather than acting on the record's presence, and evaluate against today when you use it. It costs one comparison and prevents the most confusing class of bug in this integration — a person who becomes a manager three weeks early.
1export function isActiveOn(employee, date = new Date()) {2 const start = new Date(employee.startDate);3 const end = employee.terminationDate ? new Date(employee.terminationDate) : null;45 if (date < start) return false;6 if (end && date > end) return false;78 return employee.status === "active";9}
Take less than you are offered
HR systems hold salary, home address, national identifiers, performance ratings and medical leave. A connector may be able to read some of it; your product almost certainly does not need any of it.
Request the narrowest scope that supports your feature, document what you take and why, and be able to answer that question in a security review without checking. The cheapest way to protect sensitive data is not to hold it.
What to test
- 1A new starter with a future start date. They must not appear as active before that date.
- 2A termination with a future date. Access must persist until the date, then be flagged rather than cut.
- 3A department transfer, to confirm your role or entitlement logic re-evaluates.
- 4A person present in HR but absent from the directory, and the reverse. Both must be visible somewhere rather than silently dropped.
- 5A full sync run twice in a row, to confirm the second changes nothing.