IT Service Management (ITSM) teams are increasingly turning to generative AI (GenAI) to streamline workflows, reduce resolution times, and improve user satisfaction. In this post, we’ll explore two architectures for integrating GenAI into platforms like ServiceNow: man-in-the-middle (human-in-the-loop) and agentic automation (autonomous AI agents).
Why GenAI for ITSM?
Ticket overload: Teams handle hundreds of tickets daily, leading to burnout and delays.
Knowledge gaps: Agents struggle to find relevant solutions quickly.
Repetitive tasks: Manual triage and updates consume valuable time.
GenAI can automate classification, suggest solutions, and even resolve incidents-but how you integrate it matters. Let’s compare two approaches.
In this approach, GenAI acts as an assistant to human agents. It analyzes tickets, suggests actions, and automates tasks but requires human approval before execution.
1. Set Up ServiceNow Outbound REST Integration (javascript)
// ServiceNow Scripted REST API (Outbound) var request = new sn_ws.RESTMessageV2(); request.setEndpoint('https://your-middleware.com/process-ticket'); request.setHttpMethod('POST'); request.setRequestBody(JSON.stringify(current)); var response = request.execute();
2. Build Middleware (Python/Flask Example)
from flask import Flask, request, jsonify import openai
3. Human Review & Action Agents review GenAI’s suggestions in a dashboard and approve/reject them.
Architecture 2: GenAI Agentic Automation
Here, GenAI agents act autonomously within guardrails. They analyze tickets, execute actions (e.g., resolving incidents, updating KBs), and only escalate exceptions to humans.
# GenAI analysis prompt = f""" Resolve this ticket autonomously if possible. Provide a solution and mark as closed. Ticket: {ticket['description']} """
# Auto-resolve if confidence is high if "reset password" in ai_response.choices[0].message['content'].lower(): update_data = { "state": "6", # Resolved "close_notes": "Automatically resolved: Password reset instructions sent." } requests.patch(snow_url, json=update_data, headers=headers, auth=auth)
2. Guardrails for Safety
Limit permissions (e.g., agents can’t modify user roles).
Log all actions for auditing.
Escalate tickets containing keywords like “outage” or “data breach” to humans.
Key Considerations
Combined Architecture Diagram:
Best Practices for Both Architectures
Data Privacy: Mask PII/PHI in tickets before sending to GenAI APIs.
Feedback Loops: Let agents rate AI suggestions to improve models.
Tooling: Use frameworks like LangChain for complex workflows.
Conclusion
Whether you choose man-in-the-middle or agentic automation depends on your risk tolerance and use case. Start with a hybrid approach: use autonomous agents for simple tasks (e.g., FAQs) and human-in-the-loop for critical workflows. As trust in the system grows, expand automation cautiously.
GenAI is set to redefine ITSM, propelling organizations from automation to true intelligence. The journey is just beginning-those who embrace this shift will not only optimize IT operations but also unlock new levels of agility, resilience, and innovation. The future of ITSM is not just faster or cheaper-it’s smarter, more adaptive, and profoundly more human.
In this blog post we will explore how to order items from a ServiceNow catalog using the ServiceNow REST API. There are a few examples out there that use “REST API Explorer” inside ServiceNow. I will focus here on how to do it from an external tool. In particular I am going to provide instructions for Postman. This post is the stepping stone for this follow up post where I try to solve an interesting use case of providing multi-cloud with governance through ServiceNow. You can get the Postman collection I am using from this GitHub repo.
This is the latest addition to a series of popular ServiceNow related posts:
There is also a follow up post that uses what I am covering here to allow developers to provision multi-cloud IT resources while observing any governance that might have been implemented in ServiceNow.
In the post about creating Incidents we covered the “REST API Explorer” tool in more detail. Please refer to that one if you are new to it. In this post we will use the “Service Catalog API“. In this screenshot you can see it is a very extensive API. It provides 47 API calls as of time of this writing.
Postman
Now let’s move to Postman. Feel free to use any other REST API developer tool you are used to. If you want to follow along you can retrieve my Postman collection from this GitHub repo. The Postman collection provides 3 folders. In this post we will use the “Catalog Request” folder. The other 2 folders contain the API calls that were used in 2 previous posts in this series mentioned above.
Requesting items from catalogs can be done in two ways that mimic the behavior of the user in the GUI:
order now
add to cart and submit the cart
Add to Cart and Submit order
This is a 2-step process but it might be more convenient if you are planning to order multiple items in the same request.
add an item to the cart
submit the cart
Adding an item to the cart is done with the following API call. Please replace {instance} with your particular ServiceNow instance.
POST https://{instance}.service-now.com/api/sn_sc/servicecatalog/items/{sys_id}/add_to_cart
There are 3 things you need to include:
“sys_id“. This is the “sys_id” of the item itself. As you can see it needs to be included in the URL
“sysparm_quantity“. This is the quantity of this item you want to add to the cart. It is included in the “Body” parameter and it is required
“variables“. This is also in the “Body” and needs to include all the information that you would normally provide through the GUI when creating the request. In my case this catalog entry allows me to request the installation of an application on a virtual machine. At a minimum you will need to include all variables that are defined as “mandatory” in your catalog. In my example below I am going to request the installation of an application on an existing virtual machine. You can see I am requesting the installation of Apache web server on a VM called “albtest3_01” which lives in my “sin” datacenter
If all goes well, you should get a status code of 200 and the details of the cart will be provided in the response.
You can find out the “sys_id” of the catalog item by browsing to the item itself in your catalog. It will be included in the URL itself as seen here
Alternatively you can use other calls in the “Service Catalog API” to get it programmatically. One example could be executing this call and looking for the “name” of the item you want:
GET https://{instance}.service-now.com/api/sn_sc/servicecatalog/items
You can also find out programmatically what variables you need to include with the following API call. It returns information about every parameter the specific item defined by “sys_id”. Use the “name” fields as the keys in your “Body” parameter. Also pay attention to whether variables show as “mandatory: true“.
GET https://{instance}.service-now.com/api/sn_sc/servicecatalog/items/{sys_id}/variables
Notice how the response is providing even the valid “choices” for a variable that has been configured as a “select box”.
At this point you have an item in the cart. You could potentially add other items to the cart but if you need things to be ordered in a certain sequence order 1 item at a time and orchestrate them all in your Infrastructure as Code tool of choice. The final step is to “submit the order”. This is done with the following API call
POST https://{instance}.service-now.com/api/sn_sc/servicecatalog/cart/submit_order
This API call is also part of the Postman collection you downloaded. As you can see in the screenshot below, even though this is a POST call, it doesn’t require a “Body” payload. If successful you should get a status code of 200 and the “Body” of the response will contain the “requests number”.
Order now
This is the most straight forward process as it consists of a single REST API call. It uses the “Buy Item (POST)” call. This is the call as shown in REST API Explorer.
This call needs the same payload that we used to add an item to the cart, ie the quantity and the specific variables that are typically provided in the form in the GUI.
As you can see, this API call returned a request number instead of cart details because the request was created in a single step. In the following screenshot we can see the request in the “Requests” application in the GUI.
And in the details of the “Request Item” we can see that the information we specified in the body of the API call was used to create the request.
Next steps
Postman allows you to generate code in your language of choice, ex: Python, Golang, etc. You can use this to include what we have covered into a larger script that runs additional tasks.
Alternatively, you might want to use configuration management or provisioning tools like Ansible or Terraform to order items from the ServiceNow catalog.
Ansible provides the URI module to interact with web services. As discussed above make sure the URL includes the “sys_id” and that the “Body” includes the quantity and the variables that are mandatory in that catalog
However, while showing the demos and having conversations with customers, I can see a question coming up more often. How do we cope with errors? It makes sense that this question is coming up now. We are taking the automation conversation out of the realm of the datacenter and elevating it all the way to the end-user in the ITSM world. This means “Enterprise” requirements, which in turn means less room for failure. Also, if we expose it to the end-user we are no longer talking about dozens of engineers, now we have potentially thousands of possible consumers.
A sample architecture like shown in the videos is as follows:
The requirements are:
let the user know that the workflow didn’t complete so that they are not sitting there waiting. Depending on the error they might want to retry
inform the engineers that a specific workflow is failing and they need to look into it
This can and should be done both at the ServiceNow level and the Ansible level. In this post we are going to focus on the Ansible side of things. Most mature organizations use RedHat Ansible Automation Platform. I have also included the old name Ansible Tower because somehow is still stuck in people’s heads … it is certainly shorter and easier to pronounce. Of course this is also applicable to AWX, the community support edition
From an Ansible syntax perspective you can do error handling with things like “blocks and rescue” or other techniques. However, our guiding principle here is not so much to make sure the playbook continues despite errors and ends gracefully. What we want in this case is to make sure that both the engineer and/or user gets notified. For this purpose I find the “Notifications” functionality does the job nicely. You can find “Notifications” on the left bar under the Administration menu. If you click the “Add” button you get a menu like this
After providing a name you need to select the notification “Type”. Depending on your selection a number of relevant configuration options are shown. For example if email is selected it will ask for IP and port of the SMTP server and so on. Once you fill those details scroll to the very bottom and slide the “Customize messages” button. This will reveal the syntax of the notification messages. The tool supports sending notification on 7 different types of events including start, error, time out and even the outcome of an approval. Notice how the prepopulated messages use variables with the double curly bracket syntax.
In my example I have created a notification to send emails to a Zimbra SMTP server we have in the lab. As you saw in the previous image is called “Zimbra email”. For testing purposes I have created a job template that runs a playbook called “wrong.yml”. This is single task playbook that uses the “uri” module to access a webpage. I have fed the task with an IP address that doesn’t exist, so the playbook will fail
From the template we click in the “Notifications” tab. It will show you all the notifications you have configured. In my example “Zimbra email” is the only one. On the right side you will have the opportunity to enable any of the available notifications when the template starts, succeeds or fails. If you do the same thing for a “workflow template” it will show an additional slide button named “Approval”
All is left to do is to run the template. When I run it fails as expected and I get an email in my Inbox with the following message. Notice how the body of the email maps to the syntax we saw in the “Customize messages” menu
These messages could be sent to a group of engineers that look after the platform. I particularly like the fact that there is a “Webhook” type. This opens the possibility of sending a notification to a Teams channel which is a more popular choice than email these days. You can see in this previous post how to send notifications to a Teams channel. Additionally it would make sense to create an incident automatically in your ITSM tool. Some time ago we also published a tutorial to show you how to create incidents in ServiceNow programmatically.
In this tutorial we are going to use a practical example to show you how to use the ServiceNow REST API. I personally find ServiceNow has great online documentation but I like to see some examples to understand how other people are using it. This is the motivation for this tutorial and for the previous one on ServiceNow incidents with REST API. Let’s get to it!
Introduction
The CMDB (Configuration Management Database) in ServiceNow is a key component that underpins multiple services. Most organizations nowadays have a requirement to automate services delivery in order to achieve greater agility and efficiency. If we are going to implement automation in ServiceNow sooner or later we need to deal with the CMDB and the way to do this is to use the REST API.
In this tutorial we will explore this by using a Postman collection you can find in this GitHub repo. If you need code in a specific language, Postman can help you generate code for any of the API calls in the collection. The collection also contains REST API calls to manage Incidents in ServiceNow. These calls were used in a previous tutorial called “Creating ServiceNow Incidents via REST API” which showed some examples on how to address one of the most common tasks organizations are willing to automate in ServiceNow.
If you are reading this more than likely you know what a CMDB now, so I won’t provide much detail here. The main thing to know is that the CMDB is organized in a large hierarchy of tables. At the top of the hierarchy we have the “cmdb” table and from that a single child called “cmdb_ci”. This last table is the parent for everything else. (services, applications, servers, networks, databases …).
All objects in this database are called “Configuration Items” or “CI” for short. You can show all the items by typing “cmdb_ci.list” in the “Navigator”. My developer instance has more than 2800 CI’s. The “class” parameter tells us what type of CI it is and as you will see it is a very important detail when dealing with the REST API.
The CMDB is accessed in the ServiceNow interface with the “configuration” application. Once you type “configuration” in the “Navigator” you can scroll down to see everything it contains.
The REST API
When working with a new REST API, the first step is to learn how to authenticate. In that regard, the ServiceNow REST API is straight forward as you can use basic authentication, ie username and password.
There are two main tools available to learn what API calls are available: the online product documentation and the REST API Explorer. In the online documentation you have to find the “REST API Reference” and then scroll down to “CMDB Instance API“. This is publicly accessible. In the following screenshot you can see it contains 7 REST API calls that allow you to do a range of CRUD operations.
Notice how the API calls have the “classname” URL parameter. This corresponds to the “class” we mentioned earlier. Every piece of information one would expect to find (parameters, headers, status codes …) is provided in this documentation
The second tool is the “REST API Explorer”. This a a great tool that allows you to build your API calls in a graphical manner, including the “body” payload for POST /PUT/PATCH calls. I showed how to use it in the previous tutorial “Creating ServiceNow Incidents via REST API“. However, given the sheer amount of attributes available for all classes of CI’s I am going to suggest a different way of doing this
Learning with a practical example
Let’s say we have an automation script that creates and configures a Linux virtual machine and as part of the same script now we want to add an entry for the virtual machine in the CMDB. The following API call is the one we need to use in order to create the CI:
This POST call requires a request “body” parameter which can have a large number of attributes as well as inbound/outbound relation information, ie how this CI is related to other CI’s. To help us configure the “body” we are going to:
create manually a sample resource of the same class (ie. a Linux server in this case) and configure it the way we need it. It is important to configure every attribute we want to use
use a GET call for that resource. The response will serve you as a very good reference for the “body” of the POST call we want to automate
We type “configuration” and scroll down to “Servers” and click on “Linux”. Once in “Linux Servers”, click “New” to create a new Linux server. I have filled in those fields that are relevant to my use case.
Once ready, you can click submit and the new CI will be created.
At this point, you might want to add information on how this CI is related to other CI’s. This will be very useful for example to see what services/applications are impacted if there is an incident on this CI. In my example let’s say I want to show that this Linux server depends on a storage volume. Follow these steps:
Open the CI you have just created
Scroll down to “Related Items”
On the right click the “+” symbol next to “Search for CI” to open the “Relationship Editor”
This opens the “Relationship Editor” as seen below. Now you can select the type of relationship and use the filter tool to search for the CI it depends on, ie a storage volume in our example. Then tick the CI and click the “+” symbol to add the relationship
In my case I have also created an additional relationship with an application named “Alberto Inventory app”. For the application I chose the “Used by” relationship, meaning that the application is the one that “depends on” the Linux server. In the resulting “Relationships” table below you can see both relationships and the parent/child relationship:
Back in Linux server record we can see at a glance the resulting relationships in the “Related Items” section. Notice how this is showing an additional relationship “Used by – Alberto Inventory Service”. I didn’t explicitly declared this relationship but I had an existing relationship between this service and the application. So in the end the service also depends on this Linux server
Now it is time to use Postman to see what the payload looks like. Download the collection and create 2 environment variables “pwd” and “instance” as instructed in the GitHub repo. At this point you can open the “Get CMDB Linux servers” call and click “Send”. This will return a list of Linux servers. But for each of them only the “sys_id” and the “name” are displayed.
Copy the the “sys_id” of your newly created Linux server CI and open the “GET CMDB Linux server details” call in Postman. In the URL you can the “sys_id” to the end of the URL (see highlighted in yellow) and click “Send”
This is now showing a very good approximation of the “body” parameter we were after including attributes as well as inbound/outbound relations. Notice though, how it is nested under “result”. Notice also how the JSON payload is showing all the attributes, including attributes were not displayed in the form when we created the resource. Any attribute we didn’t specify during CI creation will be empty. At this point you can make a note of any extra attributes you want to include in your payload.
Now in Postman let’s open the “select the “POST Create CMDB Linux server” call. This will create a second server called “alblinux02” with the same relationships as the server we created manually. Open the “Body” tab to see the JSON payload.
The most significant change we need to make to the output of the GET call is to modify those attributes whose value was a “dictionary” with three keys (“display_value”, “link” and “value”). These kind of attributes are in the “attributes” section as well as in the “inbound and outbound relations” sections. What we need to do is to replace the whole dictionary value with just the “sys_id” which happens to be the “value” field in the GET call output
Now we can click “Send” and the new Linux server CI will be created. You will get the status code “201 Created”. Now in the Linux servers app you should see both Linux servers.
And if you want to see the whole stack end-to-end you can go to the “application” and click on “Show Dependency views”
Supplementary API calls
You might have noticed in the request “Body” of the POST call that I included several “sys_id”. While you can get “sys_id” in the ServiceNow GUI by using right-click, ultimately if you want to automate a process you will have to get that information programmatically. For that purpose the Postman collection includes three API calls to help you get “sys_id” you need:
CMDB relationship types
CMDB users
CMDB CI
In the screenshot below you can see the three supplementary API calls highlighted in yellow. In the response to the “relationship types” call you would have to locate the item in the list with the “name” of the relationship you need and then extract its “sys_id”.
The process is very similar if you need to extract the “sys_id” of a “user” or a “CI” with the other two API calls
Tips and tricks
It might happen that when you build the payload for a POST call, like the “Create CMDB Linux server” you might accidentally omit a mandatory attribute. You could go to the documentation to see what the mandatory attributes are, but one thing I found really useful is that the ServiceNow REST API let’s you know what you are missing in the error message. In the screenshot below I removed the “discovery_source” attribute and sent the API call. As you can see the error message let’s me know exactly what the problem is.
One thing to bear in mind is that by default GET api calls return only 1000 records. If you are looking for a certain “CI” in order to extract its “sys_id” it might well happen that you have more than 1000 CI’s in the CMDB and the CI is not in the output. In that case you can use the “sysparm_query” parameters to narrow down the search or use the parameter “sysparm_limit” to retrieve more than 1000 records. You will notice in the Postman collection how the “Get CMDB CI” call is using “sysparm_limit” to retrieve 10000 records.
That was a long post! Thanks for putting up with me for the last 15 mins 😉 I hope you found this tutorial useful.
The very first thing to do when working with a REST API is to get your hands on the reference guide and hopefully the getting started guide if there is one. The first thing to look for is how to authenticate with the API and whether there are any requirements for special headers or things like that. Afterwards things tend to flow faster and easier. Fortunately, ServiceNow supports basic authentication so there is no learning curve there, although it does support more secure authentication through OAuth if you need it
In terms of documentation the online help is great. Here you can get an overview of the API. And this is the starting point for the online REST API reference. There are many branches or child API’s hanging of this root. In the screenshot below you can see how, for every call, the online help shows the URL (default or for a specific version) and parameters (path, query and request body). Further down it shows headers for the request and the response and even two coding examples for curl and python … as complete as it gets
But the tool you will learn to love very quickly is the “REST API Explorer”. Please note that this is a tool that you can only access from within your instance. Once you log in go to “System Web Services” and then locate “REST API Explorer” as shown here
You will then end up with a menu like this. Notice how you can select the specific child API in the top-left corner and the version of your environment.
ServiceNow stores all data in tables. This is also true for Incidents which unsurprisingly are stored in the “incident” table. To manipulate tables we need to use the Table API. Different HTTP methods will enable us to do the various CRUD operations. For example if we want to create an incident we will have to use the POST method. Notice in the previous image how I have selected the “Table API” and within that API the “Create a record (POST)” call. Then on the right I have selected the “incident” table.
When you scroll down you can see a dialog that allows you to build the request body for the incident creation. With the drop-down menu you can select from all the available fields. As you select new fields and assign values, the REST API Explorer builds the body for you in the text box immediately below. At the very bottom you can generate code in multiple languages
We have grouped the API calls we are using in this article into a Postman collection. You can download the collection from the following the following GitHub repo :
The collection uses 2 variables that you must add to an environment. If you are new to Postman environments check out this older article:
{{pwd}}. This is the password for the “admin” user of your ServiceNow instance. If you need to use a different user, you can change it in the collection settings
{{instance}}. This is your ServiceNow instance name, i.e. excluding the “.service-now.com” suffix. If you don’t have one or you cannot test this with your production instance, you can open your very own developer instance with ServiceNow
The collection provides 4 calls and a saved example for each call:
Get details for all incidents. This will produce a 98 line JSON structure for each incident
Get details for a single incident. This requires you to pass the “sys_id” of the incident as part of the URL as shown below. You can get the “sys_id” for a specific incident from the body of the response during the creation (POST) operation
Create incident (POST). The JSON Body parameter can take “a lot” of fields but you can start small. For example the following Body produces the incident below:
Modify incident (PUT). This will allow you to make changes to incidents. In particular you can use it to resolve/close incidents by setting the state to “7” as shown in the screenshot below. This call also requires you to pass the “sys_id” of the incident you are modifying as part of the URL
In this article we have used the REST API to interact with ServiceNow because this is the way I will do it in the upcoming video demo. But depending on what you are trying to do you might want to use Ansible. In that case you can use the official Ansible modules provided by ServiceNow themselves. The collection is available in Ansible Galaxy and provides just two modules designed to interact with ServiceNow tables. Follow the instructions in the Ansible Galaxy page to install the dependencies including the “pysnow” Python library