Skip to main content

Paycom HR Source

nexusID integrates with Paycom as an authoritative HR source and drives the full joiner/mover/leaver (JML) lifecycle from it — no SailPoint or third-party connector required. nexusID is the IdP + governance platform, so Paycom data flows straight into provisioning, deprovisioning, access reviews, and the tamper-evident audit chain.

How it flows

Paycom (SFTP CSV or REST API)
→ PaycomProvider.fetchRecords() (integration/hr-paycom)
→ PaycomConnector.upsert() (match by employeeId)
→ LifecycleEventService onJoiner / onMover / onLeaver
→ LifecycleScheduleExecutor (PROVISION → ENABLE → DISABLE)
→ Entra / AD / SCIM / downstream provisioning + deprovisioning
→ HR source precedence + WorkflowEngine (JOINER / MOVER / LEAVER)

Lifecycle decisions live in the application layer; the provider only owns the external Paycom concern, so the two delivery modes below are interchangeable from the pipeline's point of view.

Add Paycom as an HR_SOURCE integration in Admin → Integrations — no environment variables, no redeploy. Pick the Paycom provider and fill in the config form (rendered from the provider's schema): the delivery mode (SFTP or API) and the matching fields — SFTP host / username / password (or privateKeyPath) / remotePath, or API apiBaseUrl / apiEmployeesPath / apiSid

  • apiToken. Secrets are encrypted at rest, and the unified HR sync sweep picks it up. See HR Sources for the model.

Paycom — Add HR source connection fields

Legacy: environment-variable configuration

The PAYCOM_SYNC_* variables below are an optional alternative for GitOps / air-gapped deployments that keep secrets out of the database. They're off by default — most operators should use the admin console above.

Mode 1 — SFTP flat-file (env, legacy)

Paycom exports an employee CSV to SFTP; nexusID pulls and parses it on a schedule.

PAYCOM_SYNC_ENABLED=true
PAYCOM_SYNC_MODE=SFTP # default
PAYCOM_SYNC_HOST=sftp.paycomonline.com
PAYCOM_SYNC_USERNAME=...
PAYCOM_SYNC_PASSWORD=... # or PAYCOM_SYNC_PRIVATE_KEY_PATH=/path/key
PAYCOM_SYNC_REMOTE_PATH=/outbound/employees.csv
PAYCOM_SYNC_CRON="0 0 */6 * * *" # every 6h
PAYCOM_SYNC_STRICT_HOST_KEY_CHECKING=true # production

Expected CSV columns (snake_case or CamelCase, missing columns tolerated): employee_id (required, match key), email, first_name, last_name, display_name, department, job_title, manager, status.

Mode 2 — Paycom REST API (env, legacy)

Pull from Paycom's API instead of a file. Endpoint, auth, response shape, and field names are all configurable, so the client adapts to your Paycom contract.

PAYCOM_SYNC_ENABLED=true
PAYCOM_SYNC_MODE=API
PAYCOM_SYNC_API_BASE_URL=https://api.paycomonline.net
PAYCOM_SYNC_API_EMPLOYEES_PATH=/api/v1/employee
PAYCOM_SYNC_API_SID=... # + PAYCOM_SYNC_API_TOKEN=... → Basic auth
PAYCOM_SYNC_API_RECORDS_PATH=data # omit if the response body IS the array
PAYCOM_SYNC_API_PAGE_PARAM=page # omit for a single request

Authentication options:

  • SID + token → nexusID builds a Basic base64(sid:token) header, or
  • Raw header → set apiAuthHeader + apiAuthValue (e.g. Authorization: Bearer <token>).

Field mapping

Each canonical field maps to a dot-path within one employee JSON object. Defaults match snake_case names; override apiFieldMap for Paycom-native names (e.g. eecode, nested name.first):

CanonicalDefault pathExample override
employeeId (required)employee_ideecode
emailemailwork.email
firstName / lastNamefirst_name / last_namename.first / name.last
department / jobTitledepartment / job_titledeptDesc / work.title
manager / statusmanager / statussupervisor / employmentStatus

status is upper-cased; values like TERMINATED/TERMED/INACTIVE trigger the leaver path.

Scheduling & near-real-time

PaycomSyncScheduler polls on PAYCOM_SYNC_CRON (default every 6h). Lower the interval (e.g. 0 */15 * * * *) for near-real-time change detection. Changes are detected by diffing material attributes per employeeId.

Multi-source precedence

When Paycom is one of several HR feeds, HR Source Precedence decides which source wins per attribute (default order includes PAYCOM). Provenance is tracked per field.

Outbound (nexusID → Paycom write-back)

nexusID can push nexusID-originated lifecycle changes back to Paycom: termination on leaver and (optionally) attribute updates on mover. It's off by default and never writes to your payroll system of record unless explicitly enabled and configured. Writes are best-effort — a Paycom write failure never breaks the JML flow — and Paycom-originated events are skipped so they aren't echoed back.

Per Paycom's API, auth is APISID/APIToken headers (or Basic / OAuth Bearer), termination is DELETE /employees/{id} (or a status update), and updates are PUT/PATCH /employees/{id}. All of this is configurable, since Paycom's write API varies by tenant.

PAYCOM_SYNC_OUTBOUND_ENABLED=true
PAYCOM_SYNC_OUTBOUND_BASE_URL=https://api.paycom.com/v1
PAYCOM_SYNC_OUTBOUND_AUTH_STYLE=HEADERS # HEADERS (APISID/APIToken) | BASIC | RAW
PAYCOM_SYNC_OUTBOUND_SID=... PAYCOM_SYNC_OUTBOUND_TOKEN=...
PAYCOM_SYNC_OUTBOUND_EMPLOYEE_PATH_TEMPLATE=/employees/{id}
PAYCOM_SYNC_OUTBOUND_TERMINATE_MODE=DELETE # DELETE | STATUS
PAYCOM_SYNC_OUTBOUND_UPDATE_METHOD=PUT # PUT | PATCH
PAYCOM_SYNC_OUTBOUND_UPDATE_ON_MOVER=false # set true to push attribute changes too

For STATUS-mode termination, set PAYCOM_SYNC_OUTBOUND_TERMINATE_STATUS_FIELD / ...TERMINATE_STATUS_VALUE (default status = Terminated).

Implemented by PaycomWriteClient (integration/hr-paycom) + PaycomOutboundService (api/scim), invoked from the leaver/mover hooks in LifecycleEventService.

Where it lives in code

  • Provider: modules/integration/hr-paycom/.../PaycomProvider.kt (+ PaycomApiClient.kt)
  • Connector + scheduler + config: modules/api/scim/.../connector/paycom/
  • Lifecycle: LifecycleEventService, LifecycleScheduleExecutor (see Reconciliation)