The pattern: instanceList plus a search endpoint

A worker prompt in an Extend page is an instanceList that searches Workday as the user types, rather than loading every worker up front. Give it a searchEndPoint that points at a deferred endpoint calling the Staffing service's workers?search=, and bind the results with searchResultValues. Workday's documentation and sample apps build their "Relationship Manager" and "Counted By" prompts this way.

"endPoints": [
  {
    "name": "worker",
    "baseUrlType": "workday-staffing",
    "url": "workers/me",
    "authType": "sso"
  },
  {
    "name": "workerSearch",
    "baseUrlType": "workday-staffing",
    "url": "<% 'workers?search=' + instanceListQuery %>",
    "exclude": "<% empty(instanceListQuery) %>",
    "authType": "sso",
    "deferred": "true"
  }
]
{
  "type": "instanceList",
  "id": "assignedWorker",
  "label": "Assigned To",
  "searchEndPoint": "<% endpoints.workerSearch %>",
  "searchResultValues": "<% workerSearch.data %>",
  "values": "<% [worker] %>",
  "selectedValues": "<% [worker] %>",
  "required": true,
  "valueOutBinding": "createRequest.assignedTo.id"
}

What each piece does:

  • instanceListQuery is a predefined variable holding what the user typed into an instanceList that uses searchEndPoint. Workday URL-encodes it automatically when you use it in the endpoint URL.
  • "deferred": "true" stops the endpoint running on page load; the prompt calls it when the user searches. The exclude keeps it from firing with an empty string.
  • endpoints.workerSearch is how a widget refers to an endpoint by name, through the predefined endpoints variable.
  • searchResultValues takes the list the search returns. The Staffing workers collection returns id and descriptor on each row, which is what instanceList displays and stores by default.

The sample's own note on its prompt describes the behaviour: the field defaults to you, and the user can type a name and press Enter to pick someone else.

What Workday's search parameter matches

The Staffing REST service's GET /workers documents search as a case-insensitive search by name or worker ID, and a space-delimited string runs as an OR search. So "Logan 21001" returns matches for either term. The same endpoint offers parameters that shape the result:

  • includeTerminatedWorkers: include terminated workers. Leave it off for an assignment prompt; turn it on for a lookup that must find leavers.
  • filterByOrgVisibility: return only workers whose supervisory organizations the processing user can see. This requires the "Enable Restrictions on Worker Prompts Based on Supervisory Org Visibility Settings" setting in Edit Tenant Setup - System.
  • limit: default 20, maximum 100 rows per response.
  • email: return only workers whose email matches.

Add them to the URL after the search term, for example:

"url": "<% 'workers?search=' + instanceListQuery + '&includeTerminatedWorkers=true&limit=50' %>"

These parameters are from the current Staffing version in the REST API Explorer. Check the version your app's workday-staffing data provider points at, since older versions offer fewer.

Security decides who appears

The search runs as the signed-in user ("authType": "sso"), so it returns only workers that person may see. In the Staffing service the workers collection is secured by domains including Self-Service: Current Staffing Information and Worker Data: Public Worker Reports. If a tester sees fewer people than expected, that is the tenant's security working, not a bug in the prompt; check their access on those domains before changing the PMD.

That also means a prompt can't be used to widen access. Filtering the list in script, for example to hide some workers, changes what the prompt shows, not what the user is allowed to read through the API.

Inside a grid or panelList, use onSearch

searchEndPoint has a global page context. In a grid row or panelList panel it doesn't know which row triggered the search, so a search that depends on another cell in that row can't work through it. The onSearch event knows its row or panel, gives you the typed text in event.query, and can invoke a deferred endpoint. It must return a list with id and descriptor (or your idKey and displayKey).

{
  "name": "workerLookup",
  "baseUrlType": "workday-staffing",
  "url": "<% 'workers?search=' + term.urlEncode() %>",
  "authType": "sso",
  "deferred": true
}
"cellTemplate": {
  "type": "instanceList",
  "id": "rowWorker",
  "values": "<% [] %>",
  "onSearch": "<%
    empty(event.query) ? [] : (workerLookup.invoke({'term': event.query}).data ?? [])
  %>"
}

Here you encode the term yourself: urlEncode is the documented function for query-parameter values. onSearch, searchEndPoint and searchValues are mutually exclusive on one instanceList, and Workday notes that values still has to be initialised when the page loads, hence [].

The same event handles a prompt narrowed by another field. Workday's example reads an employee ID typed into the prompt, looks up that worker, and returns the members of their supervisory organization; the cascading lists guide covers prompts driven by an earlier selection.

Showing a saved worker when the page reopens

Edit pages trip over a rule in selectedValues: its IDs must be a subset of the IDs in values. A search-driven prompt has no values until someone searches, so a saved worker ID in selectedValues on its own shows nothing.

Two documented fixes:

  • Load the saved worker as the only value, as the sample does with the current user: "values": "<% [savedWorker] %>" with "selectedValues": "<% [savedWorker] %>", where savedWorker is an endpoint returning that one worker. Wrapping a single record in [ ] turns it into the list both attributes expect.
  • Use selectedValuesAndDescriptors with a list of id and descriptor pairs, for example the worker reference already stored on your business object. It doesn't need to be a subset of values.

Both attributes apply only when the page loads; to change the selection from an event handler, call setValue([id]). The selectedValues guide goes deeper on this.

Details that make it feel native

  • multiSelect: true lets the user pick several workers; valueOutBinding then sends a list.
  • widePrompt: true renders the prompt wider, which helps with long descriptors.
  • required: true blocks submit until a worker is chosen.
  • On a view page, an instanceList of workers can show the related actions menu if the data carries a Workday ID: set widKey to the field that holds it.

Test it as the users who will use it

Run the page in App Preview or the tenant and check four searches: a full name, a partial last name, a worker ID, and a name the user shouldn't be able to see. Then open the app's Logs tab on the Developer Site: a search that failed leaves a responseError entry with the HTTP status and the request URL, which tells you whether the term reached the Staffing service. Finally, save a record, reopen it in edit mode, and confirm the prompt shows the saved worker.

Testing as the people who will use the page matters here more than usual, because results depend on the searcher's security. kiweely can open the page in the browser as each of those roles in a client's test tenant and compare what each sees, which catches the "manager sees nobody" case before go-live.

Sources checked