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

ItemNotes
B2B onboarding enabledRequired on your Incode tenant
OAuth2 API Clientclient_credentials grant: save Client ID and Secret
API KeyFrom Dashboard
Integration Reference IDFrom Dashboard: identifies the workflow
Auth URLhttps://auth.demo.incode.com/oauth2/token (demo)
API URLhttps://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:
DomainAccess
National ID IdentificationGet and Put
  1. Under Business Process Security Policy Permissions, add:
Business ProcessPermission Type
Change Government IDsInitiating 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": "[email protected]",
  "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 typeIssuing countryWorkday code
passportIN (India)IND-PAS
passportJP (Japan)JPN-PAS
passportBY (Belarus)BLR-PAS
national_idUSUSA-SSN
national_idMXMEX-CURP
passportUSUSA-SSN

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


Workday SOAP: Critical Notes

TopicDetail
OAuth token placementBearer token in HTTP Authorization header, not in WS-Security SOAP header
Services hostSandbox: impl-services1.wd12.myworkday.com (different from UI host impl.wd12.myworkday.com)
SOAP endpointhttps://{services-host}/ccx/service/{tenant}/Human_Resources/v43.0
Person referenceUse Person_Reference (not Worker_Reference) inside Change_Government_IDs_Data
Verification datexsd:date format, YYYY-MM-DD only, no time component
Country reference typeISO_3166-1_Alpha-2_Code
ID type referenceNational_ID_Type_Code
Replace_AllSet to false to preserve existing IDs

Troubleshooting

ErrorCauseFix
Incode invalid_clientWrong client secretRe-paste INCODE_CLIENT_SECRET directly, do not retype
Incode 406 Not AcceptableMissing api-version headerAdd api-version: 1.0 to session creation request
Incode Employee by login factor cannot be foundEmail not in IncodeUse an email that exists in the Incode tenant
Workday 404 on token endpointWrong hostUse services host, not UI host
Workday invalid_client (OAuth)Misread client ID/secretPaste directly from Workday, don't retype
Workday invalid username or passwordTenant has disabled SOAP Basic AuthSwitch to OAuth refresh_token grant
SOAP The task submitted is not authorizedMissing BP security policyAdd ISU group to Change Government IDs BP Initiating Actions
SOAP Invalid Subelement Worker_ReferenceWrong SOAP schemaUse Person_Reference inside Change_Government_IDs_Data
SOAP PASSPORT is not a valid National_ID_Type_CodeGeneric codes don't existUse country-specific code e.g. IND-PAS
SOAP Invalid ID type Country_IDWrong type attributeUse 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