Skip to main content

HRIS sync (joiner / mover / leaver)

An HRIS (HR information system) integration makes your HR system the source of truth for who works here. LumoAuth pulls the employee directory on a schedule (or when the provider sends a webhook), compares it with the organization's users, and applies three kinds of change:

Lifecycle eventWhat LumoAuth does
Joiner — an active employee with no LumoAuth accountCreates the user (or sends an invitation), sets name and attributes, and adds the department group
Mover — an existing user whose HR record changedUpdates name, title, department and group membership; reactivates a rehire
Leaver — an employee the HRIS reports as terminatedDeactivates the account, removes group memberships, and revokes every session and OAuth token. Only accounts the sync itself provisioned or previously linked are affected, and never an administrator — anything else is reported as skipped

LumoAuth never deletes a user. A leaver is deactivated so the audit trail, group history and any owned agents survive. If the same person is rehired, the next sync reactivates the existing account instead of creating a second one.

Configure it under Organization portal → Integrations → HR & directory sync, or directly at /orgs/{org}/portal/integrations/hris.

The HR & directory sync page with the connected HR systems list and the Connect a provider cards

Supported providers​

ProviderAPI LumoAuth readsCredentials you supplyWebhooks
MergeUnified HRIS GET /employees (cursor paging, expand=manager,employments,groups)API key + linked-account tokenYes
FinchGET /employer/directory plus batched POST /employer/individual and /employer/employmentAccess tokenYes
BambooHRPOST /v1/reports/custom?format=JSON (the directory omits status and termination dates)API key + company subdomainNo
RipplingGET /employees/include_terminated, falling back to GET /employeesAPI access tokenNo
HiBobPOST /v1/people/search with showInactive: trueService user id + tokenNo
PersonioPOST /v1/auth then GET /v1/company/employeesClient id + client secretNo
WorkdayA Report-as-a-Service (RaaS) custom report published as JSONIntegration System User name + password, report URLNo

Every provider is normalised into the same employee record — external id, work e-mail, first / last / display name, department, job title, manager e-mail, employment status, start date and termination date — so the sync engine never sees a vendor-specific shape.

BambooHR and Workday let you override the column names under Column mapping when your report uses custom labels.

Setting one up​

  1. Create the API credential at the vendor (the configure page links to the exact page in each vendor's console and lists the scope needed).
  2. Open the provider's tile under Connect a provider, paste the credential and any vendor field (subdomain, report URL, base URL). Secrets are encrypted at rest and are never shown again — leave a secret field blank to keep the stored value when you edit other settings. Click Connect … (for example Connect Workday) to save.
  3. Press Test connection. LumoAuth makes one cheap read call and reports what it saw ("Connected to Merge — employee data is visible for the linked account") or the vendor's own error.
  4. Leave Dry run only on and press Sync now. The run report lists every action the sync would take, with no changes made.
  5. When the report looks right, turn dry run off, pick a schedule and enable the integration.

The Connect Workday form with the enable switch, display name, RaaS report URL and ISU credentials

Outbound calls only go to public HTTPS hosts, pin the resolved IP against DNS rebinding and time out after 10 seconds.

Options​

OptionDefaultEffect
Add users to a group named after their departmentoffGroups are created on demand; when someone moves department the membership moves with them. Only groups the sync created are populated: an existing group with the same name (for example an administrators group), or any group carrying system or administrator-conferring roles, is never joined, so HR data cannot grant LumoAuth privileges.
Invite new hires by e-mail instead of creating accounts directlyoffSends the standard invitation; the account is created when the person accepts
Deactivate leaversonTerminated employees are deactivated, sessions and OAuth tokens revoked, group memberships removed. Applies only to accounts the sync created or linked (they carry the provider identity); an account that merely shares the e-mail address, or any administrator, is reported as skipped
Provision pre-hires before their start dateoffEmployees in a pending / onboarding state are reported as skipped until they become active
Dry run onlyoffEvery sync — scheduled, webhook or manual — produces a report and changes nothing
Scheduledaily (preselected on a new integration)manual, hourly (min. 55 min apart) or daily (min. 23 h apart)

These options are in the Sync behaviour section of the provider form.

The Sync behaviour section with the schedule and the sync option switches

Matching and idempotency​

Employees are matched to users in this order:

  1. External identity — a hris:{provider} identity storing the HRIS employee id. This survives an e-mail change, so renaming someone's mailbox is a mover, not a joiner plus a leaver.
  2. Work e-mail, lower-cased and validated. Records without a usable e-mail address are reported as skipped.

Because matching is by stable external id, running the same sync twice is a no-op: the second run reports every employee as unchanged. Records that fail individually are counted as errors and the run continues.

A single run processes at most 50 000 employee records, so a mis-scoped HRIS filter cannot deactivate a whole directory in one pass.

Running a sync​

  • Portal — Sync now on the integration page queues an asynchronous run (RunHrisSyncMessage); the runs list refreshes when it finishes.
  • Schedule — LumoAuth runs every enabled integration that is due on its schedule.
  • Webhook — Merge and Finch can notify LumoAuth on employee changes.

Every run is recorded with counts (joiners, movers, leavers, unchanged, skipped, errors) and a per-employee action report. Open a run to see exactly which account was created, updated or deactivated and why. Reports longer than the row cap are truncated and the overflow is counted.

Inbound webhooks (Merge and Finch)​

Point the provider at:

POST https://<your-host>/orgs/{org}/hooks/hris/merge
POST https://<your-host>/orgs/{org}/hooks/hris/finch

The provider form shows the exact URL under Webhook (optional). Paste the signing secret into the webhook secret credential field of the form (Webhook signature key for Merge, Webhook secret for Finch). Without a stored secret the endpoint answers 403 webhook_not_enabled — LumoAuth never accepts an unsigned HRIS event.

The Connect Merge form with the API key, linked account token and webhook signature key, and the webhook URL in the side panel

ProviderHeaderSignature
MergeX-Merge-Webhook-SignatureHMAC-SHA256 of the raw body; base64url, standard base64 and hex encodings are accepted
FinchFinch-Signature: v1=<hex> + Finch-TimestampHMAC-SHA256 of "{timestamp}.{body}"; the timestamp must be within 300 seconds

The signature is verified before any organization data is touched. The payload itself is never trusted as identity data: a valid event only triggers a full pull from the provider's API, so a forged or replayed body cannot inject an employee record. Bodies over 1 MB are rejected.

Deliveries are also throttled and de-duplicated:

  • The endpoint accepts at most 60 deliveries per minute per source IP and per organization + provider; beyond that it answers 429 rate_limited.
  • A delivery whose signature was already seen in the last 24 hours is acknowledged with 202 {"duplicate": true} and triggers nothing.
  • While a webhook-triggered sync is still queued for the integration, further events are acknowledged with 202 {"coalesced": true} and fold into that run; the next event after the run starts queues a new one.

Troubleshooting​

SymptomCause
"… rejected the credentials (HTTP 401)"The API key, token or ISU password is wrong, or it lost the employee-read scope
"BambooHR: a valid company subdomain is required"The subdomain field contains a full URL or invalid characters — use just the part before .bamboohr.com
"Workday: the RaaS report URL is required"Paste the report's JSON web-service URL; LumoAuth appends format=json if it is missing
Everyone shows as skippedThe records have no usable work e-mail, or they are pre-hires and Provision pre-hires is off
Webhook returns 401 invalid_signatureThe stored webhook secret does not match the one in the provider's console, or the request was replayed outside the skew window