
ServiceNow, as a third-party platform, provides robust capabilities to develop custom webhook handlers that can directly receive and process external events in real time. These webhook handlers can be easily integrated with HPE GreenLake webhooks, allowing for smooth communication between systems. This flexibility enables teams to automate a wide range of workflows and trigger specific actions based on customer-defined requirements. By enabling seamless integration with other tools and services, this feature significantly enhances operational efficiency, reduces manual intervention, and ensures faster response to critical business events. Below are the steps to set up ServiceNow, develop a webhook handler, and integrate with the HPE GreenLake unified events framework to receive real-time events.
Optional step 1: Login and setup of a ServiceNow instance
Note: You can ignore Step 1 if you already have a ServicesNow instance.
- Create a ServiceNow developer instance in ServiceNow using the following link: https://signon.service-now.com/
- After signing in, click on the Request Instance found at the top right corner of the screen.
- Once requested, it will take a minute to provision the instance, click on the profile to check what the status is. The status should be Online.
- Click on Manage instance password from the INSTANCE ACTION list, as shown above. Here, you will find the details about your ServiceNow instance such as its URL, username, and password. Log in to your instance URL with the provided credentials.
Step 2: Create a webhook endpoint
- Once logged into your ServiceNow instance, click on All, search, and click on scripted rest api.
- Click on New in the top-right corner and fill in the Name. Click outside the box. The App Id will automatically pop up. Then, click on submit.
- Once it has been successfully submitted, you can search in the scripted REST API using the same name you created (ex: unified events)., Click on that record, scroll to bottom, and click on New.
- Now, fill in the details: i.e. give it the appropriate Name and relative path, select HTTP method to POST, uncheck Require authentication, and click on Submit.
- Paste the code snippet below in the Script section of the above created record (Change the secret in line 144).
Note: To better understand the code below, which implements the verification challenge sent to the ServiceNow handler by HPE GreenLake cloud, refer to the documentation page here or the following blog post.
// Code Snippet for GreenLake Webhook handler (function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) { var requestBody = request.body.data; var setAuth = gs.getProperty('setAuth'); if (setAuth == "true") { var reqHeaderAuthorization = request.getHeader("Authorization"); if (reqHeaderAuthorization == null || reqHeaderAuthorization == "") { response.setStatus(401); response.setHeader("Content-Type", "application/json"); var respWriter = response.getStreamWriter(); respWriter.writeString(JSON.stringify({ httpStatusCode: "401", error: "Authorization header is missing" })); respWriter.writeString("\n"); return; } else { var includesPrefixBearer = reqHeaderAuthorization.includes("Bearer"); gs.info("includesPrefixBearer " + includesPrefixBearer); if (includesPrefixBearer) { // oauth validation var token = reqHeaderAuthorization.split('Bearer')[1]; token = token ? token.trim() : ''; var validatedToken = validateToken(token); if (!validatedToken) { response.setStatus(401); response.setHeader("Content-Type", "application/json"); var respWriter2 = response.getStreamWriter(); respWriter2.writeString(JSON.stringify({ httpStatusCode: "401", error: "Authorization failed" })); respWriter2.writeString("\n"); return; } } else { // apikey validation var validatedResponse = checkAPIKEYValidation(reqHeaderAuthorization); if (!validatedResponse) { response.setStatus(401); response.setHeader("Content-Type", "application/json"); var respWriter4 = response.getStreamWriter(); respWriter4.writeString(JSON.stringify({ httpStatusCode: "401", error: "Authorization failed" })); respWriter4.writeString("\n"); return response; } } } } eventType = requestBody.type; gs.info("event type " + eventType); eventData = requestBody.data; if (eventType.includes("verification")) { gs.info("Recieved code verification request"); codeChallengeStr = requestBody.data.challengeRequest; gs.info("codeChallenege Request :" + codeChallengeStr); var generated; var resp; generated, resp = getHMACSecretFromLambda(codeChallengeStr); if (generated == false) { response.setStatus(500); response.setContentType("application/json"); var writer = response.getStreamWriter(); writer.writeString(JSON.stringify({ httpStatusCode: "500", error: JSON.stringify(resp) })); writer.writeString("\n"); return; } response.setStatus(201); response.setHeader("Content-Type", "application/json"); var writerResp2 = response.getStreamWriter(); writerResp2.writeString(JSON.stringify({ httpStatusCode: "201", verification: resp })); writerResp2.writeString("\n"); pushEventToIncidentTable(JSON.stringify(eventData), eventType); return; } else if (eventType.includes("com.hpe")) { gs.info("Recieved event with event type : " + requestBody.type); hpeWebhookSignature = request.getHeader("HPE-Webhook-Signature"); eventData = requestBody; var generatedSignature; generated, resp = getHMACSecretFromLambda(JSON.stringify(eventData)); generatedSignature = "sha256=" + resp; if (generatedSignature == hpeWebhookSignature) { gs.info("Received webhook signature are matching"); } else { gs.info("webhook signature are not same, Recieved: " + hpeWebhookSignature + " generated : " + resp); response.setStatus(412); response.setHeader("Content-Type", "application/json"); var writerResp4 = response.getStreamWriter(); writerResp4.writeString(JSON.stringify({ httpStatusCode: "412", error: "hmac signature failed to match" })); writerResp4.writeString("\n"); return; } } else { gs.warn("Not a valid request body doesn't contains type in req body"); response.setStatus(400); response.setHeader("Content-Type", "application/json"); var respWriter3 = response.getStreamWriter(); respWriter3.writeString(JSON.stringify({ httpStatusCode: "400", error: "Not a valid request body, type field is missing" })); respWriter3.writeString("\n"); return; } // push incident to incident table pushEventToIncidentTable(JSON.stringify(eventData), eventType); response.setStatus(201); response.setHeader("Content-Type", "application/json"); var writerResp3 = response.getStreamWriter(); writerResp3.writeString(JSON.stringify({ httpStatusCode: "200", })); writerResp3.writeString("\n"); })(request, response); function getHMACSecretFromLambda(codechallengeReq) { function encodeToHex(byteArray) { var hexChars = "0123456789abcdef"; var hexStr = ""; for (var i = 0; i < byteArray.length; i++) { var bt = byteArray[i] & 0xFF; hexStr += hexChars[(bt >> 4) & 0x0F]; hexStr += hexChars[bt & 0x0F]; } return hexStr; } key = "your secret"; var mac = new GlideCertificateEncryption(); var base64Key = GlideStringUtil.base64Encode(key); var base64HMAC = mac.generateMac(base64Key, "HmacSHA256", codechallengeReq); var byteArray = GlideStringUtil.base64DecodeAsBytes(base64HMAC); var hexHMAC = encodeToHex(byteArray); gs.info("hmac generated sig " + hexHMAC); return true, hexHMAC; } function pushEventToIncidentTable(description, shortDescription) { try { var gr = new GlideRecord('incident'); gr.initialize(); gr.short_description = "HPE GLCP: " + shortDescription; gr.description = description; gr.assigned_to = "admin"; gr.assignment_group = "HPE GLCP"; gr.caller_id = "System Administrator"; gr.urgency = 1; gr.priority = 1; gr.insert(); gs.info("✅ Pushed event to Incident table: " + gr.number); } catch (ex) { gs.warn("Error in pushing event to Incident table: " + ex.message); } } function checkAPIKEYValidation(apikey) { var gr = new GlideRecord("u_unified_events_api_key"); gr.query(); var response = sn_ws_int.RESTAPIResponse var apiKeyValid = false; while (gr.next()) { var now = new GlideDateTime(); var expiryTime = new GlideDateTime(gr.u_expiry_time); gs.info("expiryTime.after(now) " + expiryTime.after(now)); if (apikey == gr.u_api_key && expiryTime.after(now)) { gs.info("API key is valid"); apiKeyValid = true; break; } } if (!apiKeyValid) { gs.info(" the requested api key is not a valid key or might had expired: " + apikey); return false; } return true; } function decodeBase64Url(base64Url) { var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); while (base64.length % 4) base64 += '='; return GlideStringUtil.base64Decode(base64); } function validateToken(token) { var parts = token.split('.'); if (parts.length === 3) { var header = decodeBase64Url(parts[0]); var payload = decodeBase64Url(parts[1]); gs.info("JWT Header: " + header); gs.info("JWT Payload: " + payload); } else { gs.error("Invalid JWT token format."); return false; } var payloadObj = JSON.parse(payload); gs.info("Expires At (epoch): " + payloadObj.exp); var now = new Date().getTime() / 1000; if (payloadObj.exp && payloadObj.exp < now) { gs.error("Token is expired."); } else { gs.info("Token is still valid"); return false; } return true; }
Step 3: Set up the API key
- You can set up an API Key as an authentication method, To do this, you need to create a new table.
- Search for tables in All (header bar), look for System Definitions → Tables, and click on it, Click on New (top-right corner), fill in the details for its label name. It will auto-populate by clicking outside, Click submit. (ex: unified-events-api-key)
- Now, search in tables with above-created name, making sure to select for text as a filter. Click on the table with matched result.
- Now, add 2 more columnar fields to the table api_key and expiry_time, as shown below, with proper types by clicking on insert new rows.
- Next, search this table for unified-events-api-key in All using the search bar. Click on new to add api-keys by generating new alphanumeric key, and select expiry time by calendar pick. One can add more API keys with other expiry time for easy rotation.(https://generate-random.org/api-key-generator?count=1&length=128&type=mixed-numbers&prefix=.)
Step 4: Configure the incidents table to get notifications in ServiceNow.
This step will allow you to trigger notifications in ServiceNow so one can easily verify the triggered events.
- In All section search for Business rules (System definitions → Business rules), click on and search Abort changes, and select one, as shown below.
- Once you click on the abort changes on a group, uncheck the Insert, as shown below.
- Navigate to Business rules again and click on new to create a new rule, name it, (ex: trigger notification), select table Incident, enable checks for Active, Insert, Update, and add a filter condition (“Short description starts with HPE”), as shown below. Click on Submit.
Step 5: Call the webhook and test it with ServiceNow
- Get the webhook endpoint. To get the Resource path, navigate to Scripted Rest API then search with created REST API name.
It should look like:
- Once all the steps have been completed, call the webhook from Postman or copy the below CURL and paste it in a terminal. Make sure to change the --location url of your instance.
curl --location 'https://<dev instance>.service-now.com/api/1762185/unified_events/webhook1' \ --header 'Content-Type: application/json' \ --data '{ "name": "Grills", "status": "SOLD", "description": "Grills is a Beer", "photo_url": "http://baseurl/resourceId?action=confirm", "data":{"challengeRequest":"e37dc544569d43c73d088"}, "type":"com.hpe.verification" }'
- Now you will receive events in ServiceNow. Search for Incidents in All using the search bar, click on Assigned to me, and you should see the events triggered in table.
- Also, you will get an event notification in ServiceNow web console, as shown below.
- One can debug from the logs in case of any failures. To do so, search for System Log from All in the search bar, and click on All in System Log to see all levels of logs.
- Now, one can register the ServiceNow webhook using the secret that had been set in the script with Unified events framework, and will start receiving events in ServiceNow.
Conclusion
Leveraging ServiceNow’s webhook handling capabilities allows us to create highly responsive, automated workflows tailored to customer needs. By integrating seamlessly with existing systems, it not only streamlines operations but also enhances agility and scalability in managing real-time events across platforms.
Related

Getting started with webhooks on HPE GreenLake cloud
Feb 6, 2025