API Guide (Updated Version)

20 min read

This reference guide explains how to access Isora GRC using its Applications Programming Interface (API).

📌
Terminology:

There have been a number of updates to terminology used by Isora GRC. New terms are favored but old terminology is included in parentheses, especially where the API uses the original terminology. Many fields retain the original terminology.

Glossary - New Term / Old Term

Asset Group / Sheet

Asset / Host

Unit / Organizational Unit, Org Unit or OU

Application / App

1. Introduction to the API

Isora GRC’s API allows you to programmatically access the same set of tasks and tools that you use with Isora GRC’s web interface (GUI). There are also a few things that you can do with the API, that you can’t do with the GUI.

For example, instead of navigating with your browser to Isora GRC’s inventory page and uploading a CSV of assets to create a new sheet, you could execute a script that uploads the CSV and creates the sheet via the API. You can even automate a lot of tasks that might be cumbersome to perform on the web interface.

1.1 Accessing the Auto-generated API Documentation

The latest versions of Isora GRC include a set of automatically generated docs about the API. These docs are hosted directly on your Isora GRC instance and they include a very comprehensive list of API endpoints and supported HTTP verbs.

⚠️
The auto-generated API docs are in a prototype phase of development. Although you can expect all listed endpoints are correct, some details about supported verbs may be unreliable. If you find any errors, please report them to support@saltycloud.com

How to Access the Docs

Go to myIsoraURL/api/schema/redoc to access the docs. You must be logged into Isora GRC to view them, but you don’t need any specific role.

What Do the Docs Look Like?

1.2 How does the API work?

To access the API, required data are sent to a particular endpoint of the API. Each endpoint is labeled with a URI string (for example, something like “https://MyIsoraURL/api/sheets”).

When sending or requesting data through the API, an HTTP “verb” is used to specify the nature of your request. While these keywords are not always standardized, Isora GRC’s API follows the principles of a “RESTful API” (Representational State Transfer API). Essentially, this means that each keyword has a specific purpose and a predictable result. Not all verbs will be accessible on all endpoints. Along with the verb, API calls may include information about resources stored in the server’s databases. These resources are representations of all the different objects Isora GRC knows about, like assets, people, units, asset groups, etc.

The following table shows a list of the verbs most commonly used in a RESTful API.

GETRequest information about a resource without modifying anything
POSTRequest that the server creates a new resource
PUTRequest the server to replace (update) a resource
DELETERequest the server to remove a resource from Isora GRC

Table 1.2.1 Common API call verbs

Depending on whether the server accepts your API request, it will reply with either the requested/updated data or an HTTP error message. For example, if a user attempts an operation which is not permitted (for example, an ordinary user attempts an operation which requires superuser access), an “Error 401: Unauthorized” would be returned. There are many other possible error messages.

There are many ways to implement API calls within a programming environment, which gives you great flexibility in choosing how to manage your data. You can therefore customize your workflows based on your needs rather than being forced to work solely through clicking in the web browser interface. Most programming languages have a built-in or easily accessible module to allow for sending and receiving API information by simply plugging in the required authentication, endpoint and data needed to achieve your goals.

If working in a shell environment, built-in commands should allow you to access the API. For example, you could use the “Invoke-RestMethod” command in Windows PowerShell or “curl” in Linux or OS X.

Isora GRC uses authentication tokens to identify API users. This token, which is simply an ascii string, is included in the header of each HTTP message constructed when you make an API call.

1.3 How do I enable API access?

The API is always enabled. Before an individual user can successfully invoke the API, however, Isora GRC needs to generate an authentication token for that user. If you’re an ordinary user, you’ll need to request API access from your local Isora GRC administrator. If you’re a superuser, then follow the steps below to modify a user to add API access

  1. Log into Isora GRC’s web interface.
  1. Go to the Settings page and click on People, under the Organization section. Locate the user you wish to modify and click the pencil button next to the name to edit the user.

  1. In the Edit User dialog, click the checkbox to “Enable token API access,” then click Save.

  1. Now, when the user views their own profile, they will see the token shown. (A superuser could also view the token by viewing the user’s info in the Edit User dialog.)

    You can now copy and paste this token from the web interface and save it for use in API calls.

  1. Be aware that if you later remove a user’s API access and add it again, a new token will be generated each time.

1.4 API Structure Overview

All API endpoint URIs consist of

https://myIsoraURL/api/endpoint-specific string

In addition to specifying the correct endpoint, each API call should include the following fields in the headers of the HTTP request:

Authorization: Token <your token value>

Content-Type: application/json

An example request is demonstrated below:

The remainder of this document covers details about each individual piece of the Isora GRC API.

Note that depending on who you are, you will see somewhat different information. Just like with the web application of Isora GRC, your identity and permissions will determine what information you have access to. For example, a superuser can see the full details about another user (including that user’s token value, if one exists). An ordinary user would not be able to see token values of other users.

Some API requests can return large amounts of data, so for performance reasons, output may be returned piecemeal. For example, requesting a list of all users in Isora GRC will return a paginated list (by default, of up to 25 users at a time), with each response including links to the previous and next page of users. Most GET requests allow you specify an optional page_size parameter of up to 300.

⚠️
Be careful when specifying URIs that you don’t put a trailing slash, as this will cause the request to fail.

You can specify multiple parameters to a request by linking them together with an ampersand (&) sign.

2. Working With Organizational Data via API

Organizational data include information about users, units, permissions and locations.

2.1 Working With Users Via API

URI: https://myIsoraURL/api/users

VerbAddressNotesAdditional Details
GET/users /users?page=X &page_size=YRetrieves a paginated list of all users, Y at a time, along with their basic attributes. By default 25 responses are returned on each page.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself, which can be used to retrieve that individual user.
GET/users/<id>Retrieves an individual user, or “Not found.”
POST/usersCreates a new user. Returns the newly created user.body: {   “first_name”: string,   “last_name”: string,   “email” : string,   “username”: string,   “is_superuser”: Boolean (true/false),   “password”: string* } *optional if user exists in LDAP or AD
PUT/users/<id>Updates (replaces) existing user. Returns the user.Include the username along with any fields which you want to change.
DELETE/users/<id>Removes the user. No content is returned.
GET/users?search=string &page_size=YReturns any user objects matching the string.Useful when testing the API.

2.2 Working With Units (Org Units) Via API

URI: https://MyIsoraURL/api/orgs

VerbAddressNotesAdditional Details
GET/orgs /orgs?page=X &page_size=YRetrieves a paginated list of all units, up to Y at a time, along with their basic attributes. A default page size of 25 is used.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself, which can be used to retrieve that individual unit, as well as links to its associated permissions, child units, and assets (hosts).
GET/orgs/<id>Retrieves a unit, or “Not found.”
GET/orgs/<id>/children &page_size=YReturns an array of child units.Each one includes links to itself, its permissions, children and assets (hosts).
GET/orgs/<id>/perms /orgs/<id>/perms?page=X &page_size=YReturns a (possibly paginated) list of permissions associated with the unit.
GET/orgs/<id>hosts /orgs/<id>/hosts?page=X &page_size=YReturns a (possibly paginated) list of hosts associated with the unit, along with their basic attributes.
POST/orgsCreates a new unit. Returns the newly created unit. Note that the code and parent fields are case-sensitive.body: {   “code”: string,   “name”: string,   “parent”: string (parent code)*,   “parent_name”: string*,   “parent_long_name”: string* } *Include only one of these three optional fields to specify the parent unit, if needed.
PUT/orgs/<id>Updates (replaces) existing unit. Returns the unit.Include the code and name along with any fields which you want to change.
DELETE/orgs/<id>Removes the unit. No content is returned.If you attempt to remove a unit which has children, an error is returned. You will need to first remove the children or reassign them to another parent.
GET/orgs?search=string &page_size=YReturns unit objects matching the search string.Useful for testing.

2.3 Working With Permissions Via API

URI: https://myIsoraURL/api/perms

VerbAddressNotesAdditional Details
GET/perms /perms?page=X &page_size=YRetrieves a paginated list of all permissions, up to Y at a time. Default page size is 25.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself, which can be used to retrieve that individual permission. There are also links to endpoints for the associated user and unit (OU).
GET/perms?user=<id> /perms?user=<id>&page=X &page_size=YRetrieves paginated list of permissions of an individual user, up to Y at a time (25 by default). If an invalid user id is given, an empty response is returned.The beginning of output includes a count and links to next and previous in case the user has more than 25 permissions.
GET/perms?org_unit=<id> /perms?org_unit=<id>&page=X &page_size=YRetrieves a paginated list of permissions of a unit, up to Y at a time (by default 25). If an invalid unit id is given, an empty response is returned.The beginning of output includes a count and links to next and previous in case the unit has more than 25 permissions.
POST/permsCreates a new permission.body {   “user”: string (username),   “org_unit”: string (OU id),   “org_unit_code”: string (OU id),   “role”: Numeric (10=OU Head, 20=Assessment Manager, 30=IT Staff, 4=User) }
DELETE/perms/<id>Removes the permission. No content is returned.
GET/perms?search=string &page_size=YReturns permissions objects matching the search string.You probably want to use a fairly specific string, like a username, to avoid getting too many matches.

2.4 Working With Locations Via API

URI: https://myIsoraURL/api/locations

Verbaddressnotesadditional details
GET/locations /locations?page=X &page_size=YRetrieves a paginated list of all locations, Y at a time (25 by default). Only superusers can see confidential locations in the listing.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself, which can be used to retrieve that individual location.
GET/locations/<id>Retrieves an individual location. If an invalid location id is given, a “Not found” error is returned.
POST/locationsCreates a new location. The description and free_fields aren’t used by Isora GRC.body {   “site”: string,   “building”: string,   “room”: string,   “floor”: string,*   “confidential”: Boolean (true/false)*,   “description”: string*,   “free_fields”: json* } *optional
PUT/locations/<id>Updates (replaces) an existing location. Returns the updated location object.Include the site, building and room, along with any other fields you want to change.
DELETE/locations/<id>Removes the location. No content is returned.If any hosts are assigned to the location, the request will return an error.
GET/locations?search=string &page_size=YReturns location objects matching the string.

3. Working With Inventory Data Via API

Inventory data include assets, sheets, applications, third-party vendors and third-party vendor products.

3.1 Working With Asset Groups (Sheets) Via API

URI: https://myIsoraURL/api/sheets

VerbAddressNotesAdditional Details
GET/sheets /sheets?page=X &page_size=YRetrieves a paginated list of all assets (hosts), Y at a time (25 by default). Each object in the array includes detailed information about people and units associated with the asset group (sheet), number of assets (hosts), and notification settings.The beginning of each response includes a count and a link to the next and previous pages. Each entry in the array has a link to itself, as well as a link to assets (hosts) on that sheet and a csv page of the hosts.
GET/sheets/<id>Retrieves an individual sheet object. If an invalid location id is given, a “Not found” error is returned.
GET/sheets/<id>/csvRetrieves a CSV file containing the sheet.The file includes a header.
GET/hosts?sheet=<id> &page_size=YRetrieves a paginated list of assets (hosts) belonging to the sheet in arrays of up to Y at a time (25 by default). Each entry includes some details about the asset (host).The beginning of each response includes a count and a link to the previous and next pages Each entry in the array has a link to itself.
POST/sheetsCreates a new asset group (sheet). Returns the new asset group (sheet). Even if another owner is specified, the creator of the new asset group (sheet) is also an owner.body {   “name”: string,   “owners_people”: array of strings (usernames)*,   “owners_orgs”: array of strings (codes)* *optional
PUT/sheets/<id>Updates (replaces) an existing asset group (sheet). Returns the updated asset group (sheet) object.Include the name, along with any other fields you want to change.
POST/sheets/<id>/csvAdds contents of a CSV file to an existing asset group (sheet). The CSV file should have a header. Returns an array of errors (which is empty if there are none).Use content type multipart/form-data, use field name “file” and attach the CSV file.
DELETE/sheets/<id>Removes the asset group (sheet). No content is returned.If any assets (hosts) are assigned to it, the request will return an error.
GET/sheets?search=string &page_size=YReturns asset group (sheet) objects matching the search string.Searches both asset group (sheet) and asset (host) data, so if an asset (host) object matches the search string, it will result in a match.

3.2 Working With Assets (Hosts) Via API

URI: https://myIsoraURL/api/hosts

VerbAddressNotesAdditional Details
GET/hosts /hosts?page=X &page_size=YRetrieves a paginated list of all assets (hosts), Y at a time (by default 25). Each array entry includes details about the asset (host).The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself.
GET/hosts/<id>Retrieves an individual asset (host). If an invalid host id is given, a “Not found” error is returned.
POST/hostsCreates a new asset (host). Only the sheets field is required, which must be specified by ID. You must be the asset group (sheet) owner to add an asset (host) to any specific asset group (sheet). The new asset (host) is returned. If a location is specified, the individual components of the location object are verified to try to find a matching location ID. If an exact match cannot be found, then an error is returned and the asset (host) will not be created. The format of the location field is {   “site”: string,   “building”: string,   “floor”: string,   “room”: string }
PUT/hosts/<id>Updates (replaces) an existing asset (host). Returns the updated asset (host) object.Include the sheets field, along with any other fields you want to change.
DELETE/hosts/<id>Removes the asset (host). No content is returned.
GET/hosts?sheet=<id> &page_size=YRetrieves a paginated list of assets (hosts) belonging to the asset group (sheet) in arrays of up to Y (by default 25) at a time. Each entry includes some details about the asset (host).The beginning of each response includes a count and a link to the previous and next pages Each entry in the array has a link to itself.
GET/hosts?search=string &page_size=YReturns asset (host) objects matching the search string.Useful for testing. Only asset (host) objects are searched.

3.3 Working With Applications (Apps) Via API

URI: https://myIsoraURL/api/apps

VerbAddressNotesAdditional Details
GET/apps /apps?page=X &page_size=YReturns a count of apps along with a paginated list of all apps, Y at a time (by default up to 25). Each array entry includes details about the app.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself.
GET/apps/<id>Retrieves information about an individual app. If an invalid id is given, a “Not found” error is returned.The ID is displayed on the UI at the top of the page showing app details.
POST/appsCreates a new app. The new app is returned. If a location is specified, the individual components of the location object are verified to try to find a matching location ID. If an exact match cannot be found, then an error is returned and the host will not be added. body {   “name”: string,   “description”: string, “vertical”: string (OID of vertical),   “product”: OID of vendor product,   “classification”: string (implementation-dependent code),   [ “categories”: array of strings (implementation-dependent codes), ]   “priority”: string (code),   “contacts” : { “owners”: array of strings1 }, “deployments”: [ deployment object ],2 } 1You can specify usernames, email addresses and/or organizational unit code, but at least one OU code must be included.
PUT/apps/<id>Updates (replaces) an existing app. Returns the updated app object.The only fields required are “name” and “contacts”, but only entering those two fields will automatically change all other fields to empty. Leaving out any field in the PUT command will replace previous information with a blank field. body { “name”: string,   “description”: string, “vertical”: string (OID of vertical),   “product”: OID of vendor product,   “classification”: string (implementation-dependent code),   “priority”: string (code),   “contacts” : { “owners”: array of strings }, “deployments”: [ {“host”: <host id>,”environment”: string (code),”urls”:[]}] }
DELETE/apps/<id>Removes the app. No content is returned.
GET/apps?search=string &page_size=YReturns app objects matching the search string.Useful for testing. Only app objects are searched. ex.) /apps?search=t Returns any apps with an upper or lower case “t” in the name or description of the app.
PATCH/apps/<id>Similar to PUT command, but allows you to update one (or more) part(s) of the app at a time instead of replacing the entire app. Returns the updated app.Unlike PUT command, PATCH will NOT replace unmentioned fields with a blank field. This solely updates the one field you specifically enter. ex.) body { “priority”: string (code) }

3.4 Working With Third-Party Vendor Products Via API

URL: https://myIsoraURL/api/vendorproducts

VerbAddressNotesAdditional Details
GET/vendorproducts /vendorproducts?page=X &page_size=YReturns a count of vendor products along with a paginated list of all products, Y at a time (by default up to 25). Each array entry includes details about the product.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself.
GET/vendorproducts?search=string &page_size=YReturns any vendor products matching the search string.
GET/vendorproducts/<product id>Retrieves information about an individual vendor product. If an invalid id is given, a “Not found error is returned”.If the id of the vendor product is unknown, it can be found by GETting an app that has the vendor product as its selected product.
POST/vendorproductsCreates a new vendor product. The product is returned.body { “name”: “string”, “vendor”: “string”, “vertical”: “<vertical id>”,* “description”: “string” } *To find an unknown vertical id, follow the same process as finding an unknown vendor id and GET an app that has the desired vertical.
PUT/vendorproducts/<product id>Updates (replaces) an existing vendor product. Returns the updated vendor product.body { “name”: “string”, “vendor”: “string”, “vertical”: “<vertical id>”, “description”: “string”* } *Optional, will not overwrite previous description with a blank field if left out
PATCH/vendorproducts/<product id>Similar to PUT command, but allows you to update one (or more) part(s) of the product at a time instead of replacing the entire product. Returns the updated product.Cannot PATCH a managed product. Must include the vendor field when PATCHing a product even if you do not wish to change the vendor name. Updates only the fields specified. ex.) { “vendor”: “string”, “vertical”: “<vertical id>” }
DELETE/vendorproducts/<product id>Removes the product. No content is returned.Cannot DELETE a managed product.

3.5 Working With Third-Party Vendor Product Statuses Via API

Although they are referred to as asset statuses by the API, currently asset statuses are only applicable to third-party vendor products.

URL: https://MyIsoraURL/api/assetstatuses

VerbAddressNotesAdditional Details
GET/assetstatusesReturns a count of existing asset statuses, along with a list of them.Use the list retrieved to obtain object ids for existing asset status objects.
GET/assetstatuses?search=stringReturns any asset statuses matching the search string.
GET/assetstatus/<status id>Retrieves information about an individual asset status. If an invalid id is given, a “Not found” error is returned.The format of the returned object is: { "uuid": "object id string", "code": "alphanumeric code", "name": "string that shows up in the UI", "description": "detailed description", "active": true|false,* "assets": null* } *These fields currently do nothing.
POST/assetstatusesCreates a new asset status. The new asset status object is returned.body { “code”: “string with no hyphens”, “name”: “string”, “description”: “string” }
PUT/assetstatuses/<status id>Updates (replaces) an existing asset status. Returns the updated object.body { “code”: “string with no hyphens”, “name”: “string”, “description”: “string”* } *The description is optional and if omitted, the old description will be unchanged.
PATCH/assetstatuses/<status id>Similar to PUT command, but allows you to update one (or more) fields instead of replacing the entire asset status object. Returns the updated object.Cannot PATCH a managed asset status. Updates only the fields specified. ex: { “description”: “new and improved description string” }
DELETE/assetstatuses/<status id>Removes the asset status. No content is returned.Cannot DELETE a managed asset status.

4. Advanced API Topics

The API has a number of undocumented endpoints associated with assessments, unit questions, surveys, question categories, etc. It is unlikely that most administrators or any ordinary users would need to access these aspects of the API. Additionally, the product is under continuous development, and the API itself is always changing, so it is possible that there are new undocumented features popping up from time to time.

Fortunately, the API itself is largely self-documented. There are two approaches which are recommended for exploring the API, which may become necessary if you want to use it for some advanced purpose that hasn’t been addressed in this document.

  1. Download a REST client and use it to test and “play with” the API. Many endpoints have been outlined so far. Use your REST client to run a lot of GET requests and take a look at the data you retrieve. Many objects reference other objects and you can quickly find additional information.
  1. Look at what the web client is doing. Under the covers, the Isora GRC web interface uses the API. Using the advanced features of your web browser you can inspect the communications between your browser and the Isora GRC server to learn about the API.

The rest of this section suggests a few use cases for the Isora GRC API.

4.1 Scenario: Automatic Inventory Tracking Using the API

You always want to know what systems are in your environment. Your networking team keeps a list of all hosts which are on the network. Once per day, a list of hosts is logged. You write a script that goes down the list and looks up each host to see if it’s already in Isora GRC (you determine the criteria by which a host is recognized- MAC address, for instance). A new sheet is created in inventory containing all of the new hosts which were discovered that day. Based on where the device was detected or who logged in on it, your program notifies someone to log into Isora GRC and fill in additional details on the host, as well as moving it to the appropriate department-specific sheet.

The benefit of using the API is that it allows you to automate this process. Without the API, it would be more difficult to programmatically add these new hosts as they are discovered.

4.2 Scenario: Initial User Provisioning Via API

Your organization uses LDAP for authentication and user account management. You want all of your LDAP users to exist in Isora GRC, as well as the departments they belong to. You write a script that queries your LDAP server and invokes the API to add each user and organizational unit into Isora GRC.

4.3 Working With Policies Via API

URI: https://myIsoraURL/api/policies

VerbAddressNotesDetails
GET/policies?page=X &page_size=YReturns a paginated list of all question policies. Default number of policies per page is 25.The beginning of each response includes a count and a link to the next page. Each entry in the list has a link to itself. Use page and page_size values if desired.
GET/policies?search=string &page=X &page_size=YReturns a paginated list of all policies containing the search criteria.string refers to the search string. All fields are searched.
GET/policies/<policy id>Returns object representing the policy with a given id
POST/policiesCreates a new policy object; optionally link it to a list of existing questions (specified by their object ids){ “framework”:“string”, ”section”:”string”, “questions”: [array of question id strings]* } *Questions are optional. Question ids can be obtained by using the GET command on the /questions endpoint to retrieve a list of all questions and their ids. Format the array as follows: [ “ID1”, “ID2”, … “IDN” ]
PUT/policies/<policy id>Replaces an existing policy with an entirely new oneex: { “framework” : “string”, “section” : “string”, “questions” : [array of question strings],* “change_log” : “string”** } *Format the array as follows: [ “ID1”, “ID2”, … “IDN” ] **This refers to a changelog entry for the policy itself. Any affected questions will show “Policy updated” as their changelog entries.
PATCH/policies/<policy id>Replaces certain details of an existing policyex: { “framework” : ”string”, “section” : “new section name”, “change_log” : “string” } Note: The framework and section are both required for the PATCH command (even though they probably shouldn’t be).
DELETE/policies/<policy id>Deletes the specified policy

4.4 DRAFT: Working With Questions and Categories Via API

To work with individual questions, use

URI: https://myIsoraURL/api/questions

VerbAddressNotesAdditional Details
GET/questions /perms?page=X &page_size=YRetrieves a paginated list of questions, up to Y at a time. Default page size is 25.The beginning of each response includes a count and a link to the next page. Each entry in the list has an object id, which can be used to retrieve that individual question.
GET/questions?search=string &page_size=YReturns question objects matching the search string.All fields of the questions are searched ❓
POST/questionsCreates a new question.body {   }
DELETE/questions/<id>Removes the question. No content is returned.

To work with question categories, use

URI: https://myIsoraURL/api/questioncategories

VerbAddressNotesAdditional Details
GET/questioncategories /questioncategories?page=X &page_size=YRetrieves a paginated list of question categories, up to Y at a time. Default page size is 25.The beginning of each response includes a count and a link to the next page. Each entry in the list has an object id, which can be used to retrieve that individual question category.
GET/questions?search=string &page_size=YReturns question category objects matching the search string.All fields of the question categories are searched ❓
POST/questioncategoriesCreates a new category.body {   }
DELETE/questioncategories/<id>Removes the category. No content is returned.??what are the restrictions on removal? No children? No questions?

Did this answer your question?