This reference guide explains how to access Isora GRC using its Applications Programming Interface (API).
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.
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 hosts, people, organizational units, sheets, etc.
The following table shows a list of the verbs most commonly used in a RESTful API.
GET | Request information about a resource without modifying anything |
---|---|
POST | Request that the server creates a new resource |
PUT | Request the server to replace (update) a resource |
DELETE | Request 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
- Log into Isora GRC’s web interface.
- 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.
- In the Edit User dialog, click the checkbox to “Enable token API access,” then click Save.
- 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.
- 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 | 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.
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
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /users /users?page=X | Retrieves 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 | /users | Creates 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* } * |
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 | Returns any user objects matching the string. | Useful when testing the API. |
2.2 Working With Units Via API
URI: https://MyIsoraURL/api/orgs
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /orgs /orgs?page=X | Retrieves a paginated list of all OUs, 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 OU, as well as links to its associated permissions, child OUs, and hosts. |
GET | /orgs/<id> | Retrieves an OU, or “Not found.” | |
GET | /orgs/<id>/children | Returns an array of child OUs. | Each one includes links to itself, its permissions, children and hosts. |
GET | /orgs/<id>/perms /orgs/<id>/perms?page=X | Returns a (possibly paginated) list of permissions associated with the OU. | |
GET | /orgs/<id>hosts /orgs/<id>/hosts?page=X | Returns a (possibly paginated) list of hosts associated with the OU, along with their basic attributes. | |
POST | /orgs | Creates a new OU. Returns the newly created OU. 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* } * |
PUT | /orgs/<id> | Updates (replaces) existing OU. Returns the OU. | Include the code and name along with any fields which you want to change. |
DELETE | /orgs/<id> | Removes the organizational unit. No content is returned. | If you attempt to remove an OU 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 | Returns OU objects matching the search string. | Useful for testing. |
2.3 Working With Permissions Via API
URI: https://myIsoraURL/api/perms
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /perms /perms?page=X | Retrieves 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 OU. |
GET | /perms?user=<id> /perms?user=<id>&page=X | Retrieves 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 | Retrieves a paginated list of permissions of an OU, up to Y at a time (by default 25). If an invalid OU id is given, an empty response is returned. | The beginning of output includes a count and links to next and previous in case the OU has more than 25 permissions. |
POST | /perms | Creates 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 | Returns 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
Verb | address | notes | additional details |
---|---|---|---|
GET | /locations /locations?page=X | Retrieves a paginated list of all locations, Y at a time (25 by default). Only super-users 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 | /locations | Creates a new location. The description and free_fields aren’t used by ISORA. | body { “site”: string, “building”: string, “room”: string, “floor”: string,* “confidential”: Boolean (true/false)*, “description”: string*, “free_fields”: json* } * |
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 | Returns 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 Sheets Via API
URI: https://myIsoraURL/api/sheets
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /sheets /sheets?page=X | Retrieves a paginated list of all hosts, Y at a time (25 by default). Each object in the array includes detailed information about people and OUs associated with the sheet, number of 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 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>/csv | Retrieves a CSV file containing the sheet. | The file includes a header. |
GET | /hosts?sheet=<id> | Retrieves a paginated list of hosts belonging to the sheet in arrays of up to Y at a time (25 by default). Each entry includes some details about the 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 | /sheets | Creates a new sheet. Returns the new sheet. Even if another owner is specified, the creator of the sheet is also an owner. | body { “name”: string, “owners_people”: array of strings (usernames)*, “owners_orgs”: array of strings (codes)* * |
PUT | /sheets/<id> | Updates (replaces) an existing sheet. Returns the updated sheet object. | Include the name, along with any other fields you want to change. |
POST | /sheets/<id>/csv | Adds contents of a CSV file to an existing 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 sheet. No content is returned. | If any hosts are assigned to the location, the request will return an error. |
GET | /sheets?search=string | Returns sheet objects matching the search string. | Searches both sheet and host data, so if a 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
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /hosts /hosts?page=X | Retrieves a paginated list of all hosts, Y at a time (by default 25). Each array entry includes details about the 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 host. If an invalid host id is given, a “Not found” error is returned. | |
POST | /hosts | Creates a new host. Only the sheets field is required, which must be specified by ID. You must be a sheet owner to add a host to any specific sheet. The new 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 host will not be added. The format of the location field is { “site”: string, “building”: string, “floor”: string, “room”: string } | body { “names”: array of strings, “sheets”: array of strings (sheet IDs), “description”: string, “ips”: string, “macs”: string, “aco”: string, “location”: {location object}, |
PUT | /hosts/<id> | Updates (replaces) an existing host. Returns the updated host object. | Include the sheets field, along with any other fields you want to change. |
DELETE | /hosts/<id> | Removes the host. No content is returned. | |
GET | /hosts?sheet=<id> | Retrieves a paginated list of hosts belonging to the sheet in arrays of up to Y (by default 25) at a time. Each entry includes some details about the 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 | Returns host objects matching the search string. | Useful for testing. Only host objects are searched. |
3.3 Working With Applications (Apps) Via API
URI: https://myIsoraURL/api/apps
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /apps /apps?page=X | Returns 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 | /apps | Creates 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 } 1 |
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 | Returns 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
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /vendorproducts /vendorproducts?page=X &page_size=Y | Returns 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=Y | Returns 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 | /vendorproducts | Creates 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
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /assetstatuses | Returns 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=string | Returns 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: |
POST | /assetstatuses | Creates 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.
- 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.
- 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
Verb | Address | Notes | Details |
---|---|---|---|
GET | /policies?page=X &page_size=Y | Returns 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= | Returns a paginated list of all policies containing the search criteria. | string |
GET | /policies/<policy id> | Returns object representing the policy with a given id | |
POST | /policies | Creates 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 one | ex: { “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 policy | ex: { “framework” : ”string”, “section” : “new section name”, “change_log” : “string” } |
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
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /questions /perms?page=X | Retrieves 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 | Returns question objects matching the search string. | All fields of the questions are searched ❓ |
POST | /questions | Creates 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
Verb | Address | Notes | Additional Details |
---|---|---|---|
GET | /questioncategories /questioncategories?page=X | Retrieves 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 | Returns question category objects matching the search string. | All fields of the question categories are searched ❓ |
POST | /questioncategories | Creates a new category. | body { } |
DELETE | /questioncategories/<id> | Removes the category. No content is returned. | ??what are the restrictions on removal? No children? No questions? |