Ecosystem workforce · HR Integrations

Workday

This page covers everything a developer needs to deploy the Incode x Workday Identity Verification (IDV) middleware integration (v1 Lite).

When a new hire is created in Workday, this integration automatically sends them an Incode identity verification link. When they complete the scan, the result is written back to Workday as a Government ID record.


Integration Flow

  1. Workday Hire business process fires an HTTP callout → POST /trigger.
  2. Middleware authenticates with Incode, creates an IDV session, and returns the verification URL.
  3. Workday delivers the URL to the employee.
  4. The employee completes ID scan in Incode.
  5. Incode fires a webhook → POST /webhook.
  6. Middleware exchanges refresh token for a Workday OAuth token, then writes the IDV result via SOAP Change_Government_IDs.

Tech Stack

  • Node.js/Express (3 endpoints: POST /trigger, POST /webhook, GET /health)
  • Incode OAuth2 client_credentials flow
  • Workday OAuth2 refresh_token grant (ISU machine-to-machine)
  • Workday SOAP API v43.0: Human_Resources web service

Prerequisites

Incode

Item Notes
B2B onboarding enabled Required on your Incode tenant
OAuth2 API Client client_credentials grant: save Client ID and Secret
API Key From Dashboard
Integration Reference ID From Dashboard: identifies the workflow
Auth URL https://auth.demo.incode.com/oauth2/token (demo)
API URL https://demo-api.incodesmile.com (demo)

Warning

All session creation calls require the header api-version: 1.0. Without it, the API returns 406 Not Acceptable.

Workday

Create an Integration System User (ISU)

  1. Search Workday for Create Integration System User.
  2. Enter a Name: for example, Incode_IDV_ISU.
  3. Check Do Not Allow UI Sessions.
  4. Save.

Create a Security Group and Assign Domain Permissions

  1. Search Workday for Create Security Group and select the type Integration System Security Group.
  2. Enter a Name: for example, Incode IDV Integration.
  3. Add Incode_IDV_ISU as a member.
  4. Search Workday for Maintain Permissions for Security Group and select Incode IDV Integration.
  5. Under Domain Security Policy Permissions, add:
Domain Access
National ID Identification Get and Put
  1. Under Business Process Security Policy Permissions, add:
Business Process Permission Type
Change Government IDs Initiating Action
  1. Save.
  2. Search Workday for Activate Pending Security Policy Changes.
  3. Submit.

Register an API Client for Integrations

  1. Search Workday for Register API Client for Integrations.
  2. Enter a Client Name: for example, Incode IDV Client.
  3. Set Non-Expiring Refresh Tokens to Yes.
  4. Save.
  5. Copy the Client ID and Client Secret.

Generate a Refresh Token

  1. Search Workday for Manage Refresh Tokens for Integrations.
  2. Select the ISU, then click Generate New Refresh Token.
  3. Copy the token value.

Configure the Hire Business Process HTTP Callout

In the Hire business process, add an Integration step that POSTs to /trigger with this body:

{
  "workerID": "{{Employee_ID}}",
  "fullName": "{{Legal_Name}}",
  "personalEmail": "{{Personal_Email}}",
  "tenantURL": "https://impl.wd12.myworkday.com/ccx/service/your_tenant",
  "workdayClientId": "{{Client_ID}}",
  "workdayClientSecret": "{{Client_Secret}}",
  "workdayRefreshToken": "{{Refresh_Token}}",
  "integrationReference": "{{Integration_Reference_ID}}",
  "linkValidityMinutes": 1440
}

Environment Variables

# Incode
INCODE_CLIENT_ID=
INCODE_CLIENT_SECRET=
INCODE_AUTH_URL=https://auth.demo.incode.com/oauth2/token
INCODE_API_URL=https://demo-api.incodesmile.com
INCODE_API_KEY=
INCODE_INTEGRATION_REFERENCE=
LINK_VALIDITY_MINUTES=1440

# Workday
WORKDAY_TENANT=your_tenant_name
WORKDAY_CLIENT_ID=
WORKDAY_CLIENT_SECRET=
WORKDAY_REFRESH_TOKEN=
WORKDAY_ISU_USERNAME=Incode_IDV_ISU
AUTO_COMPLETE=true

# Middleware
PORT=3000
WEBHOOK_SECRET=       # optional — for HMAC signature validation

API Endpoints

POST /trigger

Receives the Workday callout. Creates an Incode IDV session and returns the verification URL.

Request Body

{
  "workerID": "12345",
  "fullName": "Jane Doe",
  "personalEmail": "jane@example.com",
  "tenantURL": "https://impl.wd12.myworkday.com/ccx/service/mytenant",
  "workdayClientId": "...",
  "workdayClientSecret": "...",
  "workdayRefreshToken": "...",
  "integrationReference": "...",
  "linkValidityMinutes": 1440
}

Response

{ "url": "https://incode.me/verify/..." }

POST /webhook

Receives Incode SESSION_SUCCEEDED events. If WEBHOOK_SECRET is set, validates the HMAC-SHA256 signature (header: x-incode-signature). Looks up the session context by externalCustomerId, fetches a fresh Workday OAuth token, then writes Change_Government_IDs via SOAP.

GET /health

Returns { "status": "ok" }. Use for load balancer health checks.


Deployment

Local Testing with Ngrok

npm install
cp .env.example .env    # fill in all values
node src/index.js

# In a second terminal:
ngrok http 3000
# Use the ngrok HTTPS URL as your Incode webhook endpoint

Production

npm install --production
NODE_ENV=production node src/index.js

Deploy behind a reverse proxy (nginx / AWS ALB) with TLS termination. The service is stateless except for the in-memory session store. For production, replace sessionStore with Redis.


National ID Type Code Mapping

Workday National_ID_Type_Code values are country-specific, formatted as {ISO3166Alpha3}-{Suffix}. The middleware auto-derives codes from the issuing country and document type returned by Incode OCR. Common mappings are as follows:

Incode document type Issuing country Workday code
passport IN (India) IND-PAS
passport JP (Japan) JPN-PAS
passport BY (Belarus) BLR-PAS
national_id US USA-SSN
national_id MX MEX-CURP
passport US USA-SSN

For country-specific exceptions, add entries to COUNTRY_DOC_OVERRIDES in src/utils/documentTypeMap.js.


Workday SOAP: Critical Notes

Topic Detail
OAuth token placement Bearer token in HTTP Authorization header, not in WS-Security SOAP header
Services host Sandbox: impl-services1.wd12.myworkday.com (different from UI host impl.wd12.myworkday.com)
SOAP endpoint https://{services-host}/ccx/service/{tenant}/Human_Resources/v43.0
Person reference Use Person_Reference (not Worker_Reference) inside Change_Government_IDs_Data
Verification date xsd:date format, YYYY-MM-DD only, no time component
Country reference type ISO_3166-1_Alpha-2_Code
ID type reference National_ID_Type_Code
Replace_All Set to false to preserve existing IDs

Troubleshooting

Error Cause Fix
Incode invalid_client Wrong client secret Re-paste INCODE_CLIENT_SECRET directly, do not retype
Incode 406 Not Acceptable Missing api-version header Add api-version: 1.0 to session creation request
Incode Employee by login factor cannot be found Email not in Incode Use an email that exists in the Incode tenant
Workday 404 on token endpoint Wrong host Use services host, not UI host
Workday invalid_client (OAuth) Misread client ID/secret Paste directly from Workday, don't retype
Workday invalid username or password Tenant has disabled SOAP Basic Auth Switch to OAuth refresh_token grant
SOAP The task submitted is not authorized Missing BP security policy Add ISU group to Change Government IDs BP Initiating Actions
SOAP Invalid Subelement Worker_Reference Wrong SOAP schema Use Person_Reference inside Change_Government_IDs_Data
SOAP PASSPORT is not a valid National_ID_Type_Code Generic codes don't exist Use country-specific code e.g. IND-PAS
SOAP Invalid ID type Country_ID Wrong type attribute Use ISO_3166-1_Alpha-2_Code

Go-Live Checklist

Incode

  • OAuth client created, credentials saved
  • API key configured
  • Integration Reference ID confirmed
  • Webhook URL registered pointing to /webhook
  • WEBHOOK_SECRET set and matches Incode dashboard

Workday

  • ISU created with "Do Not Allow UI Sessions"
  • Security group created, ISU assigned
  • Domain permission: National ID Identification—Get and Put
  • BP policy: Change Government IDs—Initiating Action
  • Security policy changes activated
  • API Client registered, Client ID and Secret saved
  • Refresh token generated and saved
  • Hire BP HTTP callout configured with correct field mapping

Middleware

  • All env vars populated
  • /health returns { status: 'ok' }
  • /trigger tested manually—returns IDV URL
  • /webhook tested with sample payload—writes to Workday
  • TLS enabled on public endpoint
  • Session store replaced with Redis for production

Was this page helpful?