ServiceNow REST integration with Service-Flow

Access from Service-Flow to ServiceNow

Service-Flow accesses ServiceNow with ServiceNow's Table API and Attachment API

Access from ServiceNow to Service-Flow

ServiceNow accesses Service-Flow with the same kind of web service call as Service-Flow accesses ServiceNow. With ServiceNow concepts, this is called an outbound REST message. The following chapter explains how to configure the needed REST message definitions and business rules to trigger calling the web services when inserting and/or updating incidents in ServiceNow.

Create Integration user to ServiceNow

Add integration user to ServiceNow. This user is used to send updates and creates to ServiceNow through the SOAP interface. The credentials have to match those configured to the ServiceNow adapter configuration in Service-Flow, so share the credentials with Service-Flow support.

    • Add user
      • username "serviceflow" (you can choose a different name also, but remember to change it to used business rule conditions)
      • Check "web service access only"
      • Add roles: web_service_admin
        • The user must also have access to the tables integrated, in this example incident and sys_attachment

Create an update set

It is essential to use update sets when configuring all the Service-Flow related functions to development environment. That way you ensure the fluent deployment of the integration into test & production environments.



Incident integration with REST

This paragraph describes the needed functions for setting up communication for Incident table. If other tables are needed to be integrated, make changes accordingly (highlighted definitions). Note also, that the amount of fields used in integrations might vary. The following update set includes the features in this section. Download the update set HERE.

Create new REST Message definition

You can either create a separate REST Message for every table used in the integration, or use populate ServiceNow-table element in the REST message dynamically indifferent Business Rules. 

    • Navigate to "System Web Services" -> "Outbound" -> REST MessageCreate new REST Message
      • Name: "REST call to Service-Flow"
      • Add an auth profile with the credentials you get from Service-Flow UI
      • Open HTTP Request
        • Add HTTP Header Content-Type with value application/json
      • Add a new HTTP Method
        • Name: post
        • HTTP Method: POST
        • Enpoint:
          • test: https://rest-receiver-test.service-flow.com/api
          • production: https://rest-receiver.service-flow.com/api
        • HTTP Query Parameters

          Example Query Parameters
          {
            "ServiceNow-table": "${ServiceNow-table}",
            "sys_id": "${sys_id}",
            "number": "${number}",
            "correlation_id": "${correlation_id}",
            "short_description": "${short_description}",
            "description": "${description}",
            "caller_id": "${caller_id}",
            "assigned_to": "${assigned_to}",
            "assignment_group": "${assignment_group}",
            "contact_type": "${contact_type}",
            "impact": "${impact}",
            "urgency": "${urgency}",
            "priority": "${priority}",
            "state": "${state}",
            "work_notes": "${work_notes}",
            "category": "${category}",
            "subcategory": "${subcategory}",
            "company": "${company}",
            "due_date": "${due_date}",
            "location": "${location}",
            "resolved_at": "${resolved_at}",
            "opened_at": "${opened_at}",
            "opened_by": "${opened_by}",
            "parent": "${parent}",
            "parent_incident": "${parent_incident}",
            "close_code": "${close_code}",
            "close_notes": "${close_notes}",
            "closed_at": "${closed_at}",
            "closed_by": "${closed_by}",
            "cmdb_ci": "${cmdb_ci}",
            "attachments": [${attachments}]
          }
          

Sending attachments to ServiceNow

SF sends attachments to ServiceNow through the ServiceNow's Attachment API. For this operation, outbound message to ServiceNow needs to include attribute sys_id, with the target entity's sys_id as the value.

Sending attachments to Service-Flow

Attachments are sent from ServiceNow to Service-Flow the following way. The update REST messages from ServiceNow to Service-Flow can contain attachments element that contains metadata about attachments that the incident has. The following excerpt shows example of the JSON structure:

Example of attachment XML structure
"attachments": [
    {
      "content_type": "image/png",
      "file_name": "Snip20180609_3.png",
      "size_bytes": "297940",
      "sys_id": "4ea99992db6a1f00811ddd3b5e961903"
    },
    {
      "content_type": "image/png",
      "file_name": "Snip20180609_4.png",
      "size_bytes": "297123",
      "sys_id": "4ea99992db6a1f00811ddd3b5e962121"
    }
  ]

Using this information, Service-Flow then takes the sys_id of the attachment and retrieves it from ServiceNow using the ServiceNow Attachment API.



Triggering messages out

To send messages out from ServiceNow you need to create business rules that match the pre-defined workflows. These are usually defined in process workshops where all parties are present.

Create business rule for incident

  1. Navigate to System Definition -> Business Rules
    • Click "New"
    • Name: "Service-Flow: REST from Incident"
    • Table: "Incident [incident]"
    • When: "after"
    • Check: "update" and "insert". (Condition example: current.assignment_group.name == '3rd Party Vendor' || current.correlation_id != '')
      • Copy the following example code to the Script field

Business rule for incident update
var requestBody;
var responseBody;
var status;
var sm;

if (current.sys_updated_by != 'serviceflow') {
	try{
		sm = new sn_ws.RESTMessageV2("REST call to Service-Flow", "post");
		sm.setStringParameter("ServiceNow-table", "Incident"); //Populate table name if a single REST message is used
		sm.setStringParameter("number", current.number);
		sm.setStringParameter("correlation_id", current.correlation_id);
		sm.setStringParameter("assigned_to", current.assigned_to.user_name);
		sm.setStringParameter("assignment_group", current.assignment_group.name);
		sm.setStringParameter("caller_id", current.caller_id);
		sm.setStringParameter("category", current.category);
		sm.setStringParameter("close_code", current.close_code);
		sm.setStringParameter("close_notes", current.close_notes);
		sm.setStringParameter("closed_at", current.closed_at);
		sm.setStringParameter("closed_by", current.closed_by.name);
		sm.setStringParameter("cmdb_ci", current.cmdb_ci.name);
		sm.setStringParameter("company", current.company.name);
		sm.setStringParameter("contact_type", current.contact_type);
		sm.setStringParameter("description", current.description);
		sm.setStringParameter("due_date", current.due_date);
		sm.setStringParameter("impact", current.impact);
		sm.setStringParameter("location", current.location.name);
		sm.setStringParameter("opened_at", current.opened_at);
		sm.setStringParameter("opened_by", current.opened_by.email);
		sm.setStringParameter("parent", current.parent.sys_id);
		sm.setStringParameter("parent_incident", current.parent_incident.number);
		sm.setStringParameter("resolved_at", current.resolved_at);
		sm.setStringParameter("short_description", current.short_description);
		sm.setStringParameter("state", current.state);
		sm.setStringParameter("subcategory", current.subcategory);
		sm.setStringParameter("sys_id", current.sys_id);
		sm.setStringParameter("urgency", current.urgency);

		if (current.work_notes.changes()) {
			sm.setStringParameter("work_notes", current.work_notes.getJournalEntry(1));
		}
		if (current.comments.changes()) {
			sm.setStringParameter("comments", current.comments.getJournalEntry(1));
		}		

		response = sm.execute();
		status = response.getStatusCode();

		gs.info("Resp: " + response.getBody());
		gs.info("Status: " + status);	
	} catch(ex) {
		responseBody = ex.getMessage();
		status = '500';
	} finally {
		requestBody = sm ? sm.getRequestBody():null;
	}
}

Create business rule for triggering out attachments

Here's an example how to create a business rule that send out an attachment when it is uploaded to a incident that has an external vendor's id.

Navigate to System Definition -> Business Rules

      • Click "New"
        • Name: "Service-Flow: attachment insert Incident"
        • Table: "Attachment[sys_attachment]"
        • When: "after"
        • Check: "Insert"
        • Condition: current.sys_updated_by != 'serviceflow'
      • Copy the following example code to the Script field



Business rule for triggering out attachments
if (typeof GlideStringUtil != 'undefined')
    var StringUtil = GlideStringUtil;
else
    var StringUtil = Packages.com.glide.util.StringUtil;
 
var gr = new GlideRecord('incident');
gr.addQuery('sys_id', current.table_sys_id);
gr.query();

if (gr.next()) {
    if (gr.correlation_id!= '') {
		try{
			sm = new sn_ws.RESTMessageV2("REST call to Service-Flow", "post");
			sm.setStringParameter("ServiceNow-table", "Incident");
			sm.setStringParameter("number", gr.number);
			sm.setStringParameter("sys_id", gr.sys_id);
			sm.setStringParameter("correlation_id", gr.correlation_id);
			sm.setStringParameter("comments", "Attachment uploaded via Service-Flow");
			sm.setStringParameter("priority", gr.priority);

			var attachmentsJson = '';
				attachmentsJson += ' { "content_type":"' + current.content_type + '",';
				attachmentsJson += '"file_name":"' + JSUtil.escapeText(current.file_name) + '",';
				attachmentsJson += '"size_bytes":"' + current.size_bytes + '",';
				attachmentsJson += '"sys_id":"' + current.sys_id + '"';
				attachmentsJson += '}';
			
			sm.setStringParameterNoEscape('attachments', attachmentsJson);		
			
			response = sm.execute();
			status = response.getStatusCode();

			gs.info("Resp: " + response.getBody());
			gs.info("Status: " + status);	
		} catch(ex) {
			responseBody = ex.getMessage();
			status = '500';
		} finally {
			requestBody = sm ? sm.getRequestBody():null;
		}
	}
}