Runbooks/Connector Workday

Workday HCM connector

The Workday HCM connector imports workers and supervisory organizations from your Workday tenant. IdentityMesh treats Workday as the source-of-truth for employee master data and projects worker records into the mesh, where they can be joined with downstream identity systems (AD, Entra ID, Okta) by the same join rules that already drive your AD ↔ Entra integration.

Phase 1 was REST-only and read-only. Phase 2, new in this release, adds a SOAP transport for tenants that expose Workday Web Services but not an OAuth2 API client, optional import of positions, compensation, benefits and photos, custom fields, and a deliberately narrow write-back of preferred name and work email. Pilot the phase-2 paths on an implementation tenant first.

Overview

AspectValue
DirectionInbound (Workday → IdentityMesh), plus a narrow outbound write-back of preferred name and work email
Object typesUser (Workday Workers) + OrgUnit (Supervisory Organizations); Position when ImportPositions is on
TransportsSOAP (Workday Web Services) or REST (/ccx/api/v1) for the list feeds; SOAP is always the enrichment and write-back path
Auth modeSOAP: ISU username and password sent as a WS-Security UsernameToken. REST: OAuth2 client credentials
WatermarklastUpdatedDateTime per object type
Hard-delete signalemploymentStatus == "Terminated" → IsDeleted=true
Still deferredHR provisioning (hires, job changes, terminations) into Workday; Workday Audit report integration for hard-delete detection

If you operate Workday as your HRIS and Active Directory or Entra ID as your identity provider, run this connector alongside the AD or Entra connector — they project into the same mesh objects, and the merge is governed by the join rules configured in the Admin UI (typically join on employeeNumber or email).


Prerequisites

Workday tenant setup

Choose a transport first. Tenants that expose Workday Web Services (WWS) but have not enabled OAuth2 API clients use SOAP; tenants with an API client use REST. Both need an ISU.

SOAP (ISU username and password)

  1. Create the ISU with Create Integration System User and give it a password that does not expire. Exempt it from password rotation and MFA rules the way you would any other integration account.
  2. Grant the ISU the security groups listed under REST step 2 below. Write-back additionally needs the domain security policies that allow Change_Preferred_Name and Change_Work_Contact_Information.
  3. Note the WWS endpoint version your tenant publishes; the endpoint pattern is https://{host}/ccx/service/{tenant}/Human_Resources/{version}. Set it as SoapApiVersion (below).

The ISU password is provisioned into the IdentityMesh secret store like any other secret and referenced from the connector’s authentication settings; it is sent to Workday as a WS-Security UsernameToken over HTTPS on every call.

REST (OAuth2 client credentials)

  1. Register the integration application in Workday:

    • Open Edit Tenant Setup - Security and enable OAuth 2.0 Clients for Integrations.
    • Run the Register API Client for Integrations task. Provide a friendly name (e.g. IdentityMesh-prod) and select a Workday account that becomes the integration system user (ISU).
    • On completion, Workday returns the Client ID and the one-time Client Secret. Save both immediately — the secret cannot be retrieved later.
  2. Grant the ISU read access to the worker and organization data. Recommended security groups:

    • Worker Data: Public Worker Reports
    • Worker Data: Active and Terminated Workers
    • Organization Data: View Organization

    Avoid blanket System Administrator grants. Document the exact security groups in your change-control system; Workday audits every change to ISU permissions.

  3. Test the OAuth2 token endpoint from a workstation:

    curl -X POST \
      "https://{tenant}.workday.com/ccx/oauth2/{tenant_name}/token" \
      -d "grant_type=client_credentials" \
      -u "<client_id>:<client_secret>"

    A successful response contains an access_token valid for ~30 minutes.

Configure IdentityMesh

  1. Provision the secret via secretscli. For REST that is the OAuth2 client secret; for SOAP it is the ISU password:

    secretscli set secret://workday/{tenant_name}/clientsecret "<the client secret>"
    secretscli set secret://workday/{tenant_name}/isu-password "<the ISU password>"
  2. Create the connector via the Admin UI or REST. The portal editor offers both authentication modes; pick one and it shows only that mode’s fields. Test Connection and Discover attributes run on the connector’s assigned engine instance when it is online, otherwise on another online engine instance, or on the selected relay agent; the button says which, and stays visible with the reason when none is online. Sample configJson for a SOAP tenant:

    {
      "TenantHost": "wd5-impl-services1.workday.com",
      "TenantName": "contoso_preview",
      "ApiMode": "Soap",
      "SoapApiVersion": "v46.1",
      "PageSize": 100,
      "ImportWorkers": true,
      "ImportOrganizations": true,
      "ImportPositions": false,
      "ImportCompensation": false,
      "ImportBenefits": false,
      "ImportPhotos": false,
      "ExternalIdAttribute": "id"
    }

    And for a REST tenant:

    {
      "TenantHost": "wd5-impl-services1.workday.com",
      "TenantName": "contoso_preview",
      "Realm": "contoso_preview",
      "ApiMode": "Rest",
      "PageSize": 100,
      "ImportWorkers": true,
      "ImportOrganizations": true,
      "ImportPositions": false,
      "ExternalIdAttribute": "id"
    }

    Realm typically equals TenantName; some Workday tenants distinguish between the two — check with your Workday admin.

  3. Wire the secret reference on the connector’s authentication settings. REST uses the client id plus a secret://workday/{tenant_name}/clientsecret reference; SOAP uses the ISU username plus a secret://workday/{tenant_name}/isu-password reference (Mode = UsernamePassword). IdentityMesh resolves the reference at run time. A REST tenant may carry both credential sets; the OAuth2 bearer is used for the list feeds and the ISU UsernameToken for SOAP enrichment and write-back.

  4. Add a join rule in the Admin UI mapping Workday.employeeNumber → mesh.employeeNumber (or whatever anchor your existing AD / Entra connectors use). This is what joins a Workday worker into an existing mesh object created by the IdP connector.

Settings reference

SettingDefaultWhat it does
ApiModeAuto (empty)Soap, Rest or Auto. Auto picks SOAP when only a username and password are present, and REST when only a client id and secret are present. Set it explicitly when both credential sets exist
ImportPositionsfalseImport open and filled positions as mesh object type Position (REST /positions, or SOAP Get_Positions on the Staffing service)
ImportCompensationfalseEnrich workers with compensation data from SOAP Get_Workers. Sensitive; opt in deliberately
ImportBenefitsfalseEnrich workers with benefits data from SOAP Get_Workers
ImportPhotosfalseEnrich workers with profile photos from SOAP Get_Workers
EnrichmentBatchSize25Worker IDs per SOAP enrichment call when the list feed is REST (clamped to 1–100). On the SOAP path enrichment is folded into the list page
PhotoMaxBytes262144Photos larger than this are not stored; hasPhoto and photoOmitted are still set
SoapApiVersionv42.0WWS version segment of the endpoint. SOAP-only tenants should set the version their endpoint publishes
SoapOrganizationServiceHuman_ResourcesWWS service used for Get_Organizations. Override with Staffing if your tenant serves organizations there
SoapPositionServiceStaffingWWS service used for Get_Positions. Leave ImportPositions off if the tenant has no Staffing service
WorkerCustomFields[]alias = spec lines copied onto each worker. xml:<path> reads the SOAP response (ID[@type=…] selectors, @attribute, several matches joined with ;); a plain spec is a REST property name or dot-path (on SOAP it only re-labels an attribute already imported). Discover attributes writes them
PositionCustomFields[]The same alias = spec lines for positions
PreferredNameCountryCodeUSAISO 3166-1 alpha-3 code sent with a preferred-name write-back; Workday requires a country reference on that call
PreferSoapWorkersfalseCompatibility alias from the first SOAP preview: treated as ApiMode = Soap when ApiMode is empty. Prefer ApiMode
FullImportBudgetMinutes45How long one run of a full sweep reads before it stops at a page boundary, saves its place and lets the next scheduled run continue. 0 reads the whole tenant in one run. See “Full imports run in chunks”

Adding attributes

The worker, organization and position fields in the tables below are a fixed list. Anything beyond them comes from WorkerCustomFields and PositionCustomFields (one line each, in the connector form or the raw configuration JSON). A line is alias = spec; the alias is optional. An alias may not reuse a built-in attribute name or another line’s alias, and Discover refuses to write lines that would.

Save, then run a full import; the new attribute then appears in the attribute dropdowns on join and flow rules. Workday Integration Field Overrides are not requested by the connector today.

What gets synced

Worker → User

Workday fieldIdentityMesh attributeNotes
idExternalIdWorkday’s stable WID; default ExternalIdAttribute
workerTypeworkerType“Employee” / “Contingent Worker”
employmentStatusemploymentStatus“Active”, “Terminated”, “On Leave”
derived from aboveaccountEnabledtrue when status is Active
derived from aboveIsDeletedtrue when status is Terminated
firstName / lastName / preferredNamesame
email / workEmailsame
workPhone / mobilePhonesame
employeeNumber / companyEmployeeIdsametypical join key
jobTitle / jobProfile / businessTitlesame
costCenter / costCenterCodesame
companyCode / legalEntitysame
supervisor / managermanagerthe manager’s worker id; mesh-side joins resolve to a User
location / locationCode / country / regionsame
hireDate / terminationDatesameISO 8601 date
lastUpdatedDateTime / lastUpdatedBysamedrives delta sync

Compensation, benefits and photo fields are excluded unless the matching Import* flag is on. Sensitive payroll data lives on a different audit / permission boundary, so the opt-in is explicit and per category; review the ISU’s security groups before enabling ImportCompensation.

How reference fields resolve

Workday returns most values as references: a bag of IDs of different types and, on some tenants, a Descriptor. Display attributes (country, jobProfile, location, workerType, timeType, payFrequency, payCurrency, compensationGrade, compensationPackage) resolve as the descriptor when present, otherwise the readable ID for that reference (ISO_3166-1_Alpha-2_Code for country, Job_Profile_ID, Location_ID, …), otherwise any ID that is not a WID, and only then the WID. Join keys (manager, supervisoryOrganization, primaryWorkerSupervisoryOrganization, parentOrganizationId) are always the WID, never the descriptor, so they match the ExternalId of the imported worker or organization. If you need the WID of a display reference, add an xml: line ending in ID[@type=WID].

Position (optional)

With ImportPositions enabled, each open or filled position is imported as a Position object with its own external id, so customers that model positions as first-class identities can join workers to positions with ordinary join rules. Add position fields you need beyond the defaults through PositionCustomFields.

Supervisory Organization → OrgUnit

Workday fieldIdentityMesh attributeNotes
idExternalId
namename
codecode
parentOrganizationIdparentOrganizationIdbuilds the org hierarchy
managermanagerworker id of the org owner
lastUpdatedDateTimelastUpdatedDateTime

Organization membership is not emitted as a separate GroupMember object type. Each worker carries primaryWorkerSupervisoryOrganization as an attribute, which is sufficient for downstream join rules to project users into the right group / OU. Flat membership rows remain a follow-up request.

Watermark and delta behaviour

Watermarks are ISO-8601 lastUpdatedDateTime timestamps stored per object type, encoded as a single JSON string the engine treats opaquely:

{"w": "2026-04-26T08:30:00.000Z", "o": "2026-04-26T08:25:00.000Z", "p": "2026-04-26T08:20:00.000Z"}

(w = workers, o = organizations, p = positions; the p key is present only when ImportPositions is on). Both transports use the same watermark shape.

The connector tolerates legacy bare-string watermarks for in-flight upgrades — if it sees a plain ISO timestamp instead of the wrapper, both feeds use that timestamp as their starting point.

Hard-delete gap

Workday does not typically purge worker records — terminated workers retain a Terminated employment status and remain visible in the API indefinitely. The connector maps employmentStatus == "Terminated" to a delete change with IsDeleted=true, which is the correct soft-delete signal for downstream provisioning.

If your Workday tenant is configured to purge worker records (rare, but possible for contingent workers), schedule a periodic full sync (set the connector’s Mode = Full on a weekly cadence) to catch hard-deletes. A later release will close this gap via the Workday Audit report API.

Full imports run in chunks

A full import of a large tenant takes longer than the engine’s import-run timeout (Timeout (minutes) on the Schedule page, default 60), and a run that times out keeps nothing: the watermark is not advanced, so the next attempt starts again from worker zero. Without chunking, a tenant too large to read within the timeout would fail every full import the same way.

Since this release a full sweep is resumable across runs. The connector reads pages until FullImportBudgetMinutes (default 45) is spent, stops at a page boundary, and returns what it has together with a cursor (the object type it was on and its offset). The engine commits that chunk, stores the cursor inside the connector’s watermark under a resume key, records the run with status Continuing, and leaves the schedule due, so the next one-minute scheduler tick starts the next chunk. Chunks run workers, then organizations, then positions; a resumed chunk skips the types it already finished.

What you will see on the Runs page:

Three rules follow from the design:

  1. Delete-by-absence waits for the sweep to finish. Objects not seen since the sweep started are marked deleted only when the last chunk completes, using the sweep’s start time, so a worker read in chunk 1 is not “absent” in chunk 3. A sweep that never finishes never deletes; after 100 chunks the connector logs a warning that the tenant may be growing faster than the budget allows. Raise the budget or the schedule frequency.
  2. Run now with the Full override restarts the sweep. It clears the watermark, cursor included. Let a running sweep finish its chunks instead.
  3. Delta imports never chunk. Only Mode = Full schedules, or a run that finds a cursor, sweep.

A chunk that fails keeps the incoming cursor, so a retry resumes rather than restarts. The REST feed has no stable sort, so a hire between chunks can shift offsets: a worker read twice is a harmless upsert, and a worker skipped that way is caught by the next delta. Pilot chunked sweeps on a Direct connector before routing the connector through a relay agent.

Throttling

Workday’s REST API enforces per-tenant rate limits (configurable per Workday environment). The connector handles 429 Too Many Requests responses with Retry-After-aware retry: 3 retries with exponential back-off capped at 30 seconds. Beyond that it surfaces the error to the run history.

If you see frequent 429s in the connector logs, work with Workday Support to raise the integration tenant’s rate limit — IdentityMesh makes one request per page (100 workers per page by default), so even a 100k-worker tenant fits inside the standard 1000 req/hour bucket.

Export (write-back)

Export is new in this release and is not HR provisioning. The connector writes exactly two things back to Workday, and only on User updates:

Mesh changeWorkday operation
Preferred nameChange_Preferred_Name (with PreferredNameCountryCode)
Work emailChange_Work_Contact_Information

Anything else in an export batch — an add, a delete, or an update carrying any other attribute — fails with a confirmation error that names the unsupported operation. It does not throw, so one unsupported change fails its own queue item rather than the batch, and the engine never records a change Workday did not receive.

Write-back always goes over SOAP. SOAP tenants authenticate it with the ISU UsernameToken; REST tenants reuse the OAuth2 bearer and may also send the UsernameToken when ISU credentials are configured. Grant the ISU only the two domain security policies the operations above need.

Security model

Still deferred

The following remain out of scope and are documented as follow-ups: