Showing results for 
Show  only  | Search instead for 
Did you mean: 

Working with Velocity Template Language in ITSM Ticketing

Working with Velocity Template Language in ITSM Ticketing


With disconnected systems, a common practice for handling write operations is to leverage an information technology service management (ITSM) system to handle the manual fulfillment tasks which would otherwise be collected within IdentityNow itself. Essentially, an integration can be deployed to generate service tickets directly into systems such as ServiceNow, Jira Service Desk, Cherwell, etc.

The use of such an integration allows for a great degree of flexibility and customization within the ticket's message body itself. IdentityNow allows you to dynamically inject portions of the provisioning plan into the API payload which ultimately gets sent to the ITSM system. We leverage a subset of Velocity Template Language to accomplish this, and this guide details some of the special variables which can be used to customize tickets. Additionally, examples of complicated use cases are provided to assist you in crafting your own custom ticket descriptions. 

Keywords and Variables

The below keywords can be used to reference particular aspects of the provisioning plan object which is fed into the integration's Velocity evaluator. As with all Velocity variables, these keywords must start with a dollar ($) sign:

  • $plan – The overall provisioning plan generated; this is usually used as a top-level object reference for one of the below variables.
  • $plan.arguments – The list of attributes and values generated by the system during plan generation; within the identity request XML document, these will be the entries listed under the <Plan><Attributes> node.
  • $plan.requests – An array list of account requests generated by the system during plan generation; within the identity request XML document, these will be the <AccountRequest> entries listed under the <Plan> node; there will be one entry for each linked account for that user, which is typically just one for IdentityNow.
  • $plan.request(<i>).resource - The target application of the provisioning plan. This will normally be the name of the source within IdentityNow which the integration is serving.
  • $plan.request(<i>).operation - The provisioning plan operation (i.e., Create, Modify, Disable, Delete) for the specific source account. 
  • $plan.request(<i>).items – An array list of attributes and values provided as part of the account create/enable/modify/disable profile for that account; within the identity request XML document, these will be the <AttributeRequest> entries listed under the <Plan><AccountRequest> node.
  • $plan.request(<i>).items(<j>).name – This is the name of the attribute within the referenced attribute request (e.g., email, displayName, groups, etc.)
  • $plan.request(<i>).items(<j>).Operation – This is the action being taken on the attribute within the referenced attribute request (i.e., Add, Remove, Set)
  • $plan.request(<i>).items(<j>).value – This is the value which the attribute within the referenced attribute request should be set to during an Add or Set operation.
  • $ – This is the nativeIdentity value of the user for which the account request has been initiated.
  • $plan.arguments.<name> – This will return the value of the plan argument identified by <name>

Leveraging Keywords within Velocity Template Language

Note the usage of (<i>) and (<j>) in the documentation above for both the request and items array lists. This is an indication that these objects can be multi-valued and thus any particular reference to them must have some knowledge of which item in the list is desired. However, SailPoint's implementation of the Velocity Engine only has a stateless reference to the provisioning plan -- it is passed through the evaluator only once without any sort of variable pre-calculation, so index notation such as `$items[1]` or `$request[0]` will not evaluate.

Therefore, the proper way to build the desired verbiage in your Velocity script is to construct it dynamically while iterating through the objects. Consider the following example:

#foreach($request in $plan.requests)
  $!{request.operation} account '${}' on ${request.resource}
    Additional Details:
    #foreach($item in $request.items)
      $!{item.Operation} attribute '${}' with value: ${item.value}

The Velocity Engine will run through the provisioning plan and output all of the text elements in order as it's iterating through the list of requests and items. The above code would result in something similar to:

Create account 'test.user' on System A
Additional Details:
Add attribute 'name' with value: Test User
Add attribute 'email' with value:
Add attribute 'location' with value: Austin

Sometimes, it is necessary to get some detailed information about the provisioning event from the plan's attributes in order to know what type of text to render as output. For example, you maybe have a need to output one type of message if the account request is a Create, and another type of message if the account request is a Disable. Consider the following desired requirement:

If the target application is called Application A, generate the below message:

"This access has been approved in SailPoint. Please install the local client for <user's display name> (Employee ID = <user's employeeID>). Please forward this ticket to the Application A team."

Otherwise, generate the below message:

"This access has been approved in SailPoint. Please Create an account in <target application name> with the following attributes and entitlement/s for <user's display name> (Employee ID = <user's employee ID>):
displayName = Test User
email =
location = Austin"

Here, the goal is to output one message body if the target application is "Application A," but output a different message body if it is any other application. The appropriate way to construct your Velocity Template Language code to achieve this result would be:

#foreach($request in $plan.requests)
  #set($appName = $request.resource)
#if($appName == 'Application A')
  This access has been approved in SailPoint. Please install the local client for $!plan.arguments.displayName (Employee ID = $!plan.arguments.employeeID).\nPlease forward this ticket to the $appName team.
  This access has been approved in SailPoint. Please $!plan.arguments.acctOperation an account in $appName with the following attributes and entitlement/s for $!plan.arguments.displayName (Employee ID = $!plan.arguments.employeeID):\n
  #foreach($request in $plan.requests)
      #foreach($item in $request.items)
        $ = $item.value\n

As you can see above, we are able to iterate through the plan as many times as needed, set temporary variables, and then use those temporary variables to drive the final text to generate.



I would like to know all the available methods and attributes included in the $plan object on velocity. I also tried to expose the full $plan object passing it as value to serviceNow for exploring its content, but I have been unable to see it. Any idea, help or document I can use as a reference? Thanks for your help.

Hello, I would also like to explore the entire content of the $plan object but are also unable to see it within service now trying to use .getmap() function. If anyone knows how to iterate through the plan that would be helpful.


Me too.. It would be really useful if a full document of the $plan object was released? I do understand that some aspects are specific to the request type.. But, can I see a cert ID (for example) if a revoke originated from a Certification? I am assuming not. For me, knowing it's come from a (de)Provisioning activity, IE Leaver would be very useful.. Any thoughts please?




Any documentation available to list all $plan content ?


@hari_patel agreeing with the above that a full $plan object model or a method of iterating through and outputing all attributes of $plan would be extremely helpful. Is that available somewhere? 

@gavink you can actually see the provisioning plan details in Search via the Account Activities object type. The UI will only show a portion of the full plan attributes, but if you view the API raw response, you'll notice that there is quite a bit of detail around the plan.

That being said, if you're looking to just dump all of the attributes within the `$plan` object, there's not a single method to do that (i.e., there's no corollary to the `plan.toXml()` operation). You'd need to iterate to all plan arguments, account requests, and attribute requests via your Velocity script and print that all out to either a log stream or your ticket. I wouldn't do this in any sort of production scenario, but it can be helpful for targeted troubleshooting/data validation.

we are able to create RITM ticket in servicenow, however, when we mark the RITM as closed complete, those changes are not reflecting back to SailPoint. Just an FYI, we have changed the time period to 15 minutes, but, still we are not able sync back to Sailpoint. Any help is much appreciated in Advance

Hi @bkumar592 ,
From my side, the status in SailPoint is updated from the SCTASK status, not the RITM status.
Hope it can be useful on your investigation.

For what it's worth, if you enable debugging in your cluster and log into the VAs you can see plan details in log/ccg.log

Just search for

"message": "Provisioning plan:

For example:

grep '"message":"Provisioning plan' log/ccg.log

or to make it easier to read:

grep '"message":"Provisioning plan' log/ccg.log | jq

Not sure if this is all the data available or not ....

I am using below script for one of the fields in my SDIM integration, but it is always going to else block even if I am selecting Application in if block(App1 or App2 ) while submitting a request. The content to be populated is some unique id for the service now field.

#foreach($request in $plan.requests)
#set($appName = $request.resource)
#if($appName == 'App1') 695b5df6dbf60f409734f3671d9619 #elseif ($appName == 'App2') bfccfcfb1b2e64508aea8516624bcb #else 990d5a531ba4d5502a6eeb192a4bcb #end


Can anyone help here, if you see any possible issues.


@rooppreet212 , for me, $request.resource return the source name with a suffix "[source]".

Maybe if you test ($appName == 'App1 [source]') you will have better results.

From my side, I modified the cloud rule associated with my SDIM configuration to get the source name and add it to the plan.

// Get all requests in the plan
requestList = plan.getAllRequests();
// Get a request in your request list
request = requestList.get(0);
// Get the application (source)
requestApplication = request.getApplication();
// Get the attribute by source
idn.getSourceAttributeBySourceName(requestApplication, "cloudDisplayName");

@MrGuardian_59 , Thanks that was helpful but for me it's not always AppName [source] but sometimes it's like AppName [source - someNumber], I tried checking from where exactly this is coming from and found out that it's not picking just the source name but the Account Correlation config source name which you can get by using GET source API call.



Version history
Revision #:
5 of 5
Last update:
‎Oct 12, 2021 03:10 PM
Updated by: