IncidentIQ - API & Automation

This week I decided to tackle some automation using the IncidentIQ API. The goal is to create a ticket in IncidentIQ when students are enrolled or withdrawn.

API access for IncidentIQ is disabled by default. After a quick request to their support team, a new item in the dashboard appears under Administration > Developer Tools. This is where API tokens can be created, and a link to their documentation can be found. I also came across another public facing set of API docs here.

The documentation is helpful, but little lackluster. Another email to support and some help from a user at the IncidentIQ subreddit, and I had a curl script that would create a ticket.

curl 'https://DOMAIN.incidentiq.com/api/v1.0/tickets/new' -H 'Content-Type: application/json' -H 'Accept: application/json, text/plain, */*' -H 'Authorization: Bearer APITOKEN' --data-binary $'{"Assets":[{"AssetId":""}],"IsUrgent":false,"TicketFollowers":null,"Locations":null,"Users":null,"Teams":null,"Roles":null,"AssetGroups":null,"IssueDescription":"New Student at CAMPUS. ID, NAME, GRADE","CustomFieldValues":[{"SiteId":"SITEID","CustomFieldId":"b493cc92-cb28-4846-8b23-53f4fb06b063","Scope":"Site","CustomFieldTypeId":"d70f1586-8cd4-4a32-8465-ba304ae7eb6a","EntityTypeId":"888891ac-91aa-e711-80c2-100dffa00001","IsRequired":false,"IsReadOnly":false,"IsHidden":false,"Filters":[{"FilterId":"888861e5-34ff-4fcf-87de-100d6f0e0043","Exclude":false,"Value":"d5d91f20-2269-e611-80f1-000c29ab80b0"}],"DisplayOrder":39,"EditorTypeId":12,"Value":"","IsValid":true}],"LocationId":"eeb58be9-2d9b-43da-875e-06203d0d2f46","Attachments":[],"LocationDetails":"Room details","HasSensitiveInformation":false,"Subject":"Other Request / Request New Equipment","TicketWizardCategoryId":"d5d91f20-2269-e611-80f1-000c29ab80b0","ForId":"FORID","LocationRoomId":"d1186c41-7e78-e611-80f1-000c29ab80b0","IssueCategoryId":"bcd6e0eb-bb36-e811-80c3-0003ff685cc1","IssueId":"a1243d4b-bc36-e811-80c3-0003ff685cc1","IssueTypeId":"51f8371b-bc36-e811-80c3-0003ff685cc1","IsTraining":false,"ProductId":"88df910c-91aa-e711-80c2-0004ffa00010"}'

While the curl script is handy, it’s a bit hard to read, and a python script felt optimal. I’ve configured the script to loop through a CSV exported from our student information system, for each row(student) a ticket is created. I also customized the IssueDescription to insert information about the student, and modified the location ID to assign the correct campus based on the students information.

import csv
import json
import requests
from requests.structures import CaseInsensitiveDict
#headers for request
headers = CaseInsensitiveDict()
headers["Content-Type"] = "application/json"
headers["Accept"] = "application/json, text/plain, */*"
headers["Authorization"] = "Bearer APITOKEN"
#import users
f = open("C:\data\students.csv")
csv_f = csv.reader(f)
next(csv_f)
#for each user, do the things
for row in csv_f:
name = row[2]
email = row[6]
password = row[5]
studentid = row[7]
campus = row[9]
year = row[8]
#ticket site id based on campus
if campus == '001':
site = "SITEID"
elif campus == "041":
site = "SITEID"
elif campus == "101":
site = "SITEID"
elif campus == "103":
site = "SITEID"
else:
site = "SITEID"
#ticket school name based on campus number
if campus == '001':
school = "High School"
elif campus == "041":
school = "Middle School"
elif campus == "101":
school = "Elementary School"
elif campus == "103":
school = "Primary School"
else:
school = "Administration"
#description for ticket
desc = "New student at " + school + "." + "\n \n" + "Please deploy any required devices and accessories." + "\n \n" + "Student Name: " + name + "\n" + "Student ID: " + studentid + "\n" + "Year: " + year + "\n" + "Email: " + email + "\n" + "Password: " + password
print(desc)
url = "https://DOMAIN.incidentiq.com/services/tickets/new"
payload = json.dumps({
"Assets": [
{
"AssetId": ""
}
],
"IsUrgent": False,
"TicketFollowers": "",
"Locations": "",
"Users": "",
"Teams": "",
"Roles": "",
"AssetGroups": "",
"IssueDescription": desc,
"CustomFieldValues": [
{
"SiteId": "SITEID",
"CustomFieldId": "b493cc92-cb28-4846-8b23-53f4fb06b063",
"Scope": "Site",
"CustomFieldTypeId": "d70f1586-8cd4-4a32-8465-ba304ae7eb6a",
"EntityTypeId": "888891ac-91aa-e711-80c2-100dffa00001",
"IsRequired": False,
"IsReadOnly": False,
"IsHidden": False,
"Filters": [
{
"FilterId": "888861e5-34ff-4fcf-87de-100d6f0e0043",
"Exclude": False,
"Value": "d5d91f20-2269-e611-80f1-000c29ab80b0"
}
],
"DisplayOrder": 39,
"EditorTypeId": 12,
"Value": "",
"IsValid": True
}
],
"LocationId": site,
"Attachments": [],
"HasSensitiveInformation": False,
"Subject": "Other Request / Request New Equipment",
"TicketWizardCategoryId": "d5d91f20-2269-e611-80f1-000c29ab80b0",
"ForId": "FORID",
"IssueCategoryId": "bcd6e0eb-bb36-e811-80c3-0003ff685cc1",
"IssueId": "a1243d4b-bc36-e811-80c3-0003ff685cc1",
"IssueTypeId": "51f8371b-bc36-e811-80c3-0003ff685cc1",
"IsTraining": False,
"ProductId": "88df910c-91aa-e711-80c2-0004ffa00010"
})
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

At this point, you might be curious as to the corresponding keys for in the json above. I spent more time sorting this out than I’d like to admit.

Here’s a quick rundown of where I found certain keys:SiteId – Listed in Developer Tools MenuForId – Visible in URL of user profile pageLocationId – All Locations Menu > View Page Source > href/locationIssueCategoryId, IssueId, IssueTypeId – Start a New Ticket > View Page Source > Network Tab > issues?$=999999 > Items

Once this script was completed, all that was left was to add it to a scheduled task for ticket automation.