In SailPoint, the identity has a costCenter attribute (e.g., "1261_8040128"), and I need to match this with the department’s Code value (where Code = 1261-8040128 — note the difference in delimiter).
Once matched, I need to extract the corresponding ID and send that in the provisioning payload as DepartmentID.
Dynamic Requirement
New departments are frequently added in the target system, so the solution needs to dynamically call the departments API and pick the matching one based on the current identity’s costCenter.
If i am not wrong, To achieve this you have to write the BeforeOperation Rule where you can execute your API: GET https://api.xyz.com/departments
Use the API response to check -match the costCentric values to department code and set that value in your create account body.
We have a similar issue. We didn’t need the cost center value for any other automation, so we added a transform to the Identity Profile for the source that replaces any _ with a -. Then we were able to use the Identity attribute in its current form for our other automation. If you don’t need that Identity attribute for anything else, you could do the same.
I know it’s not ideal but if you did need that attribute with the _ in it then you could add an additional Identity attribute that has the transform. So you will end up having the existing Identity attribute where the value contains the _ and then another that is nearly the same but contains the - instead.
If you want to update the DepartmentId for an existing user based on changes to the CostCentric values, it likely won’t be updated using a rule alone. If I’m not mistaken, you’ll need to write a transform where you map the CostCentric values to the corresponding DepartmentId. Then, populate that value in the DepartmentId identity attribute and sync it to the Account attribute in source. Also configure update operation in source for same.
Note:- So in this case if any new values are added in target application, every time you need to update transform.
Kindly try it out and let me know whether it helps you.
As these departments are dynamic in nature , we cannot use transform here unless we have departments data in the tenant . I suggest to use a before operation on create account .
If you want to bring in department data into tenant and compare the values , you need to implement a transform using Lookup operation .
This transform is static in nature considering the departments are dynamic . We must update the transform to add new department values in the transforms to compare .
This alone doesn’t full fill the requirement. But this answers your question how can we search exact department via matching cost center with code
Implementation Approach for Dynamic DepartmentID Resolution - High level steps:
Attribute Mapping in Create Operation
Configure the Web Services connector to map the DepartmentID field in the Create operation to the identity’s costCenter attribute. This temporary mapping is used as an intermediate input for the rule logic.
Before Operation Rule Configuration
Develop a Before Operation Rule to dynamically resolve the actual DepartmentID (GUID) prior to provisioning. The rule will:
Extract the Input Value
Retrieve the DepartmentID value from the provisioning plan. At this stage, it holds the identity’s costCenter value.
Perform External API Lookup
Use the provided restClient to invoke the target system’s /departments API and fetch the corresponding department object based on the transformed costCenter code.
Update the Provisioning Payload
Once the department record is retrieved, extract the ID field and update the DepartmentID key in the JSON payload with this value, ensuring that the final request body contains the correct GUID required by the target system.
Sample Before Operation Rule -
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import connector.common.JsonUtil;
import connector.common.Util;
import sailpoint.connector.webservices.Endpoint;
import sailpoint.connector.webservices.WebServicesClient;
import sailpoint.object.Application;
import sailpoint.object.ProvisioningPlan;
import sailpoint.object.ProvisioningPlan.AccountRequest;
import sailpoint.object.ProvisioningPlan.AttributeRequest;
import sailpoint.tools.GeneralException;
Map body = requestEndPoint.getBody();
String jsonBody = (String) body.get("jsonBody");
log.info("Rule - Modify Body: running");
try {
Map jsonMap = JsonUtil.toMap(jsonBody);
if (jsonMap != null) {
// Step 1: Get costCenter from provisioningPlan (passed in as DepartmentID attr)
String costCenter = null;
if (provisioningPlan != null) {
for (AccountRequest accReq : Util.iterate(provisioningPlan.getAccountRequests())) {
for (AttributeRequest attReq : Util.iterate(accReq.getAttributeRequests())) {
if ("DepartmentID".equalsIgnoreCase(attReq.getName())) {
costCenter = (String) attReq.getValue();
log.info("Fetched DepartmentID (costCenter) from plan: " + costCenter);
}
}
}
}
// Step 2: Convert to expected Code format
String formattedCode = null;
if (costCenter != null) {
formattedCode = costCenter.replace("_", "-");
log.info("Formatted department Code: " + formattedCode);
}
// Step 3: Call /departments?code=XYZ and extract ID
String departmentID = null;
if (formattedCode != null && restClient != null) {
// Build the endpoint (adjust if API requires path param or other format)
String endpoint = "/departments?code=" + java.net.URLEncoder.encode(formattedCode, "UTF-8");
log.info("Calling department lookup endpoint: " + endpoint);
Map deptResponse = restClient.execute("GET", endpoint, null, null, null);
if (deptResponse != null && deptResponse.containsKey("body")) {
Map deptData = (Map) deptResponse.get("body");
if (deptData.containsKey("ID")) {
departmentID = (String) deptData.get("ID");
log.info("Retrieved Department ID: " + departmentID);
} else {
log.warn("No ID found in department response: " + deptData);
}
} else {
log.warn("Invalid department lookup response: " + deptResponse);
}
}
// Step 4: Inject into final JSON payload
if (departmentID != null) {
jsonMap.put("DepartmentID", departmentID);
} else {
log.warn("Department ID not found for code: " + formattedCode);
}
String finalBody = JsonUtil.render(jsonMap);
body.put("jsonBody", finalBody);
requestEndPoint.setBody(body);
}
} catch (Exception ex) {
log.error("Rule - Modify Body Exception: ", ex);
}
return requestEndPoint;