Stitchflow
Zenefits logo

Zenefits User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 17, 2026

Summary and recommendation

The Zenefits Core API is a REST API authenticated via OAuth 2.0 Authorization Code flow, with tokens scoped per company tenant - a separate OAuth flow is required for each Zenefits organization.

The base URL is https://api.zenefits.com/core, and all requests require a Bearer token in the Authorization header.

Pagination uses limit/offset with a default page size of 20 and a maximum of 100;

the response includes a next_url field for pre-built next-page navigation.

No official SDK is published;

all integrations require raw HTTP calls.

Rate-limit values and headers are not publicly documented - contact Zenefits developer support for current thresholds before building high-frequency polling logic.

For identity graph construction, the People endpoint returns nested department and manager objects (referenced by Zenefits ID), enabling traversal of the full reporting hierarchy.

Employment records are stored separately from person records and must be joined on person.id to correlate hire date, employment type, and title into a unified identity record.

Sensitive fields such as date_of_birth may require additional OAuth scopes or admin-level app credentials.

API quick reference

Has user APIYes
Auth methodOAuth 2.0 (Authorization Code flow)
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredGrowth (formerly referred to as Pro in some sources)

Authentication

Auth method: OAuth 2.0 (Authorization Code flow)

Setup steps

  1. Register an application in the Zenefits Developer Portal to obtain a client_id and client_secret.
  2. Redirect the user to https://secure.zenefits.com/oauth2/platform-authorize/ with response_type=code, client_id, redirect_uri, and scope parameters.
  3. Exchange the returned authorization code for an access_token and refresh_token via POST to https://secure.zenefits.com/oauth2/token/.
  4. Include the access token in all API requests as a Bearer token in the Authorization header.
  5. Refresh the access token using the refresh_token grant before expiry.

Required scopes

Scope Description Required for
people:read Read employee profile data including personal info, employment status, and contact details. GET /people, GET /people/{id}
people:write Create or update employee records. POST /people, PATCH /people/{id}
employments:read Read employment details such as hire date, department, and title. GET /employments
departments:read Read department structure. GET /departments

User object / data model

Field Type Description On create On update Notes
id string Unique Zenefits person identifier. system-generated immutable Used as path param in all person-specific calls.
first_name string Employee's legal first name. required optional
last_name string Employee's legal last name. required optional
preferred_name string Preferred display name. optional optional
work_email string Primary work email address. required optional Used as login identifier.
personal_email string Personal email address. optional optional
status string Employment status (active, inactive, etc.). system-set optional Reflects hire/termination state.
department object Nested object with department id and name. optional optional References /departments resource.
manager object Nested object referencing manager's person id. optional optional
title string Job title. optional optional
start_date date Employment start (hire) date (YYYY-MM-DD). required optional
termination_date date Date of termination if applicable. optional optional Set when offboarding.
location object Work location object. optional optional
phone string Work phone number. optional optional
date_of_birth date Employee date of birth. optional optional Sensitive field; scope-gated.
gender string Gender identity. optional optional
type string Employment type (employee, contractor). optional optional
created_at datetime Record creation timestamp (ISO 8601). system-generated immutable
updated_at datetime Last modification timestamp (ISO 8601). system-generated system-updated

Core endpoints

List all people

  • Method: GET
  • URL: https://api.zenefits.com/core/people
  • Watch out for: Inactive/terminated employees are included by default; filter by status=active if needed.

Request example

GET /core/people?limit=20&offset=0
Authorization: Bearer {access_token}

Response example

{
  "data": {
    "url": "/core/people",
    "data": [{"id":"abc123","first_name":"Jane","last_name":"Doe","work_email":"jane@co.com","status":"active"}],
    "next_url": "/core/people?limit=20&offset=20"
  }
}

Get a single person

  • Method: GET
  • URL: https://api.zenefits.com/core/people/{id}
  • Watch out for: Returns 404 if the person ID does not exist or the token lacks people:read scope.

Request example

GET /core/people/abc123
Authorization: Bearer {access_token}

Response example

{
  "data": {
    "id": "abc123",
    "first_name": "Jane",
    "last_name": "Doe",
    "work_email": "jane@co.com",
    "status": "active",
    "title": "Engineer"
  }
}

Update a person

  • Method: PATCH
  • URL: https://api.zenefits.com/core/people/{id}
  • Watch out for: Not all fields are writable via API; some HR fields (e.g., compensation) require Zenefits UI or separate payroll endpoints.

Request example

PATCH /core/people/abc123
Authorization: Bearer {access_token}
Content-Type: application/json

{"title": "Senior Engineer"}

Response example

{
  "data": {
    "id": "abc123",
    "title": "Senior Engineer",
    "updated_at": "2024-06-01T12:00:00Z"
  }
}

List employments

  • Method: GET
  • URL: https://api.zenefits.com/core/employments
  • Watch out for: Employment records are separate from person records; join on person.id to correlate.

Request example

GET /core/employments?limit=20
Authorization: Bearer {access_token}

Response example

{
  "data": {
    "data": [{"id":"emp1","person":{"id":"abc123"},"hire_date":"2022-01-10","employment_type":"employee"}]
  }
}

List departments

  • Method: GET
  • URL: https://api.zenefits.com/core/departments
  • Watch out for: Department IDs are required when assigning employees to departments via PATCH /people.

Request example

GET /core/departments
Authorization: Bearer {access_token}

Response example

{
  "data": {
    "data": [{"id":"dept1","name":"Engineering"}]
  }
}

List company locations

  • Method: GET
  • URL: https://api.zenefits.com/core/locations
  • Watch out for: Location IDs are needed when setting work location on a person record.

Request example

GET /core/locations
Authorization: Bearer {access_token}

Response example

{
  "data": {
    "data": [{"id":"loc1","name":"HQ","city":"San Francisco"}]
  }
}

Get company info

  • Method: GET
  • URL: https://api.zenefits.com/core/companies/{id}
  • Watch out for: Company ID is returned during OAuth token exchange; store it for subsequent calls.

Request example

GET /core/companies/co123
Authorization: Bearer {access_token}

Response example

{
  "data": {
    "id": "co123",
    "name": "Acme Corp",
    "ein": "12-3456789"
  }
}

Rate limits, pagination, and events

  • Rate limits: Zenefits developer docs do not publicly specify exact rate-limit numbers or tiers.

  • Rate-limit headers: Unknown

  • Retry-After header: Unknown

  • Rate-limit notes: No explicit rate-limit values, headers, or Retry-After behavior documented in official sources. Contact Zenefits developer support for current limits.

  • Pagination method: offset

  • Default page size: 20

  • Max page size: 100

  • Pagination pointer: limit / offset

  • Webhooks available: No

  • Webhook notes: Zenefits developer documentation does not describe a native outbound webhook system for real-time event notifications.

  • Alternative event strategy: Poll the People API periodically using the updated_at field to detect changes, or use the Okta SCIM integration for provisioning-event-driven flows.

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Growth (formerly referred to as Pro in some sources)

  • Endpoint: Provisioned by Okta (or OneLogin) connector; Zenefits does not publish a standalone SCIM base URL. The endpoint is generated within the IdP integration setup.

  • Supported operations: Create Users, Update User Attributes, Deactivate Users, Group Push (via Okta), Schema Discovery

Limitations:

  • SCIM endpoint is IdP-connector-specific (Okta, OneLogin); no generic SCIM URL is published by Zenefits.
  • SSO must be configured before SCIM provisioning can be enabled.
  • Available on Growth plan and above; not available on Essentials.
  • Google Workspace SCIM provisioning is not supported per available documentation.
  • Password sync is not supported via SCIM; authentication is handled by the IdP SSO.

Common scenarios

Three integration patterns are well-supported by the available API surface.

First, syncing active employees to an external directory: authenticate, paginate GET /core/people with status=active, then enrich each record via GET /core/employments filtered by person.id, and upsert using work_email as the unique key

omitting the status filter will silently include terminated employees.

Second, automated onboarding via Okta SCIM: requires the Growth plan, a fully configured SAML SSO connection, and SCIM enabled in the Okta app catalog;

Okta generates the SCIM endpoint and bearer token, and provisioning errors will occur if SSO is not validated first.

Third, updating job title and department after an internal transfer: resolve the department ID via GET /core/departments, resolve the person ID via work_email lookup, then PATCH /core/people/{id} with the new title and department object

department must be referenced by its Zenefits ID, not by name string, or the request returns a 400.

Sync active employees to an external directory

  1. Authenticate via OAuth 2.0 Authorization Code flow to obtain access_token.
  2. GET /core/people?limit=100&offset=0 and filter results where status=active.
  3. Paginate using next_url until no further pages are returned.
  4. For each person, GET /core/employments filtered by person.id to retrieve hire_date and employment_type.
  5. Upsert records into the external directory using work_email as the unique key.

Watch out for: Inactive/terminated employees are returned by default; omitting the status filter will include them in the sync.

Automate employee onboarding via Okta SCIM

  1. Ensure Zenefits account is on the Growth plan or above.
  2. Configure SAML SSO between Okta and Zenefits via the Okta application catalog.
  3. Enable SCIM provisioning in the Okta Zenefits app; Okta generates the SCIM endpoint and bearer token.
  4. Assign the Okta application to a user or group; Okta pushes a SCIM Create User request to Zenefits.
  5. Verify the new employee record appears in Zenefits with correct attributes.

Watch out for: SSO must be fully configured and tested before enabling SCIM; enabling SCIM without SSO will result in provisioning errors.

Update job title and department after an internal transfer

  1. GET /core/departments to retrieve the target department's id.
  2. GET /core/people?work_email=jane@co.com to resolve the person's Zenefits id.
  3. PATCH /core/people/{id} with body {"title": "Staff Engineer", "department": {"id": "dept_new"}}.
  4. Confirm the 200 response contains the updated title and department fields.

Watch out for: Department must be referenced by its Zenefits id, not by name string; an invalid id returns a 400 error.

Why building this yourself is a trap

The Zenefits API has several non-obvious failure modes worth flagging before building production integrations. The developer portal (developers.zenefits.com) has had periods of limited maintenance; verify endpoint availability and documentation accuracy against live behavior before committing to an integration design.

Webhooks are not available - there is no native outbound event system, so change detection requires periodic polling against the People API using the updated_at field, or delegation to the Okta SCIM integration for provisioning-event-driven flows. SCIM provisioning is IdP-connector-specific (Okta or OneLogin only);

no generic SCIM base URL is published by Zenefits, and Google Workspace SCIM is not supported. Compensation and some other sensitive HR fields are not writable via the Core API and require the Zenefits UI or separate payroll endpoints, which limits the scope of fully automated lifecycle management.

Automate Zenefits workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 17, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen