API Overview
The Virgo API is the main interface to all Virgo application logic and data. It is designed to support both customer-facing applications developed by Access as well as third party applications and connectors.
The API is based on REST principles. Since REST is an architecture pattern rather than a strict protocol or method, any ambiguity in the design approach will be resolved by reviewing common practices and weighing against the needs of the developers building and using the API. There is no formal specification for REST.
Some of the design goals and constraints include:
- Common verbs and their definitions for this implementation are GET (read), POST (create), PUT (update), and DELETE (delete).
- The API does not try to support all possible verbs for every resource. It only supports the verbs needed to meet current design requirements. The API will be enhanced as required to support additional features.
- When returning data for a resource, the API will include links for child resources and, optionally by query parameter, include the child data to avoid unnecessary requests.
- Protect the system and private personal data using authentication and authorization.
- Require secure connections (SSL/TLS).
- Use standard HTTP response status codes and provide detailed error information when appropriate.
- By default, data will be returned as JSON. All examples in this document will use the JSON output.
This quick exercise will lead you through the steps of ensuring you can access the Virgo API and get the Record Series in your Retention Schedule.
-
Complete the Authentication process to obtain your access token. You will include the token in the Authorization header as Bearer <token> in the following steps and future requests to the API.
-
In a REST tool (we recommend Postman) get the Records Schedule ID via the GET/ recordsSchedules method.
Your organization's records retention schedule is a collection of Record Series objects that belong to a Records Schedule. So first get the Records Schedule ID before getting the Record Series ID. The default schedule is named "Default RRS".
For example:
GET https://api.infogovsolutions.com/rest/2/recordsSchedules?name=Default+RRS
Authorization: Bearer <token>
-
Get the ID of the Record Series associated with the Records Schedule via the GET /recordsSchedules/{recordsScheduleid} method.
For example:
GET https://api.infogovsolutions.com/rest/2/recordsSchedules/{recordsScheduleid}/recordSeries
Authorization: Bearer <token>
This exercise is complete. If successful, you could access the Virgo API and get the Record Series in your Retention Schedule.
If you need additional assistance, please contact your Professional Services project manager or Support.
TIP: You can add Searching, Filtering, Sorting, or Paging parameters for the response data.
The base URL for the current version of the Virgo API (v2) is: https://api.infogovsolutions.com/rest/2/
Detailed endpoint input and output specifications can be found in Swagger.
The API also offers a help resource that describes each endpoint in real time. See the Help Response below.
The Virgo API supports OAuth 2.0 and requires an API key to access.
-
Contact your Professional Services project manager or Support to obtain an API key.
-
Support creates an API key based on your Virgo user name and password.
-
Create a POST request for an access token from a REST tool (we recommend Postman) with these values:
URL
POST https://api.infogovsolutions.com/rest/2/auth/oauth2/token
Header
Name Value Authorization Basic <Base64Encode(clientid:secret)> Content-Type application/x-www-form-urlencoded Body
Name Value grant_type password username Your Virgo user name, typically your email address password Your Virgo user password For example:
POST https://api.infogovsolutions.com/rest/2/auth/oauth2/token
Authorization: Basic <Base64Encode(clientid:secret)>
Content-Type: application/x-www-form-urlencoded
grant_type=password
&username=virgo_user@example.com
&password=virgo_password
-
Virgo API responds with an access token. For example:
{
"access_token": "c367cbff669007e6089239dfbc7cc2360324303e",
"expires_in": 3600,
"token_type": "Bearer",
"scope": null,
"refresh_token": "60e9e3c428ea115af775c6da21307995a80cfcd5"
}
Now you can copy the access token and send API requests with a tool like Postman.
Request:
POST /rest/2/auth/oauth2/token
Host: api.infogovsolutions.com
Authorization: Basic xxxxxxxxxxxxxxxxxx
grant_type=refresh_token
&refresh_token=60e9e3c428ea115af775c6da21307995a80cfcd5
Response:
{
"access_token": "9e4945d977e0c81029842739741685f1babd8fea",
"expires_in": 3600,
"token_type": "Bearer",
"scope": null
}
The API will return one of the following response structures:
- Read Response (GET)
- Data Manipulation Response (POST, PUT, DELETE)
- Error Response
- Help Response
A read response will be returned for a request that reads but does not attempt to change data (typically GET requests).
{
"code": integer,
"message": "string",
"success": boolean,
"method": "string"
"request": "string"
"data": {
"totalItems": integer,
"currentItems": integer,
"startIndex": integer,
"totalPages": integer,
"itemsPerPage": integer,
"pageIndex": integer,
"pages": {
"first": "string",
"previous": "string",
"next": "string",
"last": "string",
}
"items": [
{
"id": "string",
"createdBy": "string",
"createdDate": "string",
"updatedBy": "string",
"updatedDate": "string",
"links": {
"self": {
"href": "string"
...
}
}
...
},
...
]
}
}
Property | Description |
---|---|
code | HTTP status code as an integer. |
message | String to explain the status code. |
success | Boolean to indicate if the request was successful or encountered an error. |
method | The HTTP verb used for the request. |
request | The original request sent to the server. This only includes the URI and the query parameters; it does not include any body content sent with the request. |
data | The main data structure containing the intended result of the request. This structure includes paging information along with an array of items. |
data.totalItems | The total number of results available for this request regardless of paging. |
data.currentItems | The number of results returned in this response / on this page. |
data.startIndex | Index of the first item on this page in relation to the total number of results. |
data.totalPages | Total number of pages available for this result. |
data.itemsPerPage | Maximum number of items on each page. This may be greater than currentItems but currentItems will never be greater than itemsPerPage. |
data.pageIndex | Page number in relation to the total number of pages. |
data.pages | Paging object with links to valid pages. |
data.pages.first | URI for the first page of the dataset. |
data.pages.previous | URI for the previous page of the dataset. This property will only exist when there is a previous page. |
data.pages.next | URI for the next page of the dataset. This property will only exist when there is a next page. |
data.pages.last | URI for the first page of the dataset. |
data.items[] | An array of objects that represent the data itself. The array will have one or more records. The array will not be empty; an error will be returned instead. |
data.items[#].id | The unique ID of the record. This is always treated as a string even if the value appears to be numeric. This property is read only. |
data.items[#].createdBy | The ID of the user that created the record. This property is read only. |
data.items[#].createdDate | Date the record was created in the W3C date format (i.e. “2013-11-05T16:34:41.000Z”). This property is read only. |
data.items[#].updatedBy | The ID of the user that created the record. This property is read only. |
data.items[#].updatedDate | Date the record was created in the W3C date format (i.e. “2013-11-05T16:34:41.000Z”). This property is read only. |
data.items[#].links | Object with links to related objects. Every links object will include a self link. It may include additional links appropriate for the resource. This property is read only. |
data.items[#].links.self | Self link object. |
data.items[#].links.self.href | URI to the current resource. |
A data manipulation response will be returned for a request that attempts to change data (typically POST, PUT, and DELETE requests).
Data manipulation requests may be sent with a single object in the body of the request or with an array of objects. If an array of objects is submitted, each object will be handled in order and independent of subsequent objects. This means that one object operation may be successful while another may fail. Accordingly, each object in the response will include status properties.
The overall status of the request will depend on the status of the individual objects. If all objects have the same return status, then that status will be reflected in the global status in the response. If status varies by object, the global status in the response will be 207 Multi-Status. A code 207 indicates that the client must inspect the status of each object in the response.
{
"code": integer,
"message": "string",
"success": boolean,
"method": "string"
"request": "string"
"data": {
"totalItems": integer,
"items": [
{
"code": integer,
"message": "string",
"success": boolean,
"responseData": {
...
},
"errors": [
{
"type": "string",
"code": integer,
"message": "string",
"location": "string"
},
...
],
"requestData": {
...
}
},
...
]
}
}
Property | Description |
---|---|
code | HTTP status code as an integer. |
message | String to explain the status code. |
success | Boolean to indicate if the request was successful or encountered an error. |
method | The HTTP verb used for the request. |
request | The original request sent to the server. This only includes the URI and the query parameters; it does not include any body content sent with the request. |
data | The main data structure containing the intended result of the request. |
data.totalItems | The total number of results returned in the response. |
data.items[] | An array of objects that represent the data itself. The array will have one or more records. The array will not be empty; an error will be returned instead. |
data.items[#].code | The HTTP status code for this item as an integer. |
data.items[#].message | String to explain the status code for this item. |
data.items[#].success | Boolean to indicate success or failure for this item. |
data.items[#].responseData | Resulting object data in the same format as an item in the Read Response. This property will only exist for the item on success. |
data.items[#].errors[] | An array of one or more errors. Each error object will have the same properties as errors in the Error Response. This property will only exist for the item on failure. |
data.items[#].requestData | Request object as it was interpreted by the server. This property will only exist for the item on failure. |
An error response may be returned for any verb and represents a problem with the request itself or with the server. Common error responses are for Access Denied, Not Found, Service Unavailable, etc.
{
"code": integer,
"message": "string",
"success": boolean,
"method": "string"
"request": "string"
"errors": [
{
"type": "string",
"code": integer,
"message": "string",
"location": "string"
},
...
]
}
Property | Description |
---|---|
code | HTTP status code as an integer. |
message | String to explain the status code. |
success | Boolean to indicate if the request was successful or encountered an error. |
method | The HTTP verb used for the request. |
request | The original request sent to the server. This only includes the URI and the query parameters; it does not include POST data. |
errors[] | Array of error messages. The array will contain at least one object. |
errors.type | Error type name. |
errors.code | Error code in the form of an HTTP status code. |
errors.message | Description of the error. |
errors.location | If the error is specific to a data property, this will be the name of the property. For error responses this property will generally be null. |
Each resource will respond to a help child resource which describes the current user’s access rights, field definitions, and related resources/links. For example, both of the following Aura’s will provide help for the company's resource:
https://api.infogovsolutions.com/rest/2/companies/help
https://api.infogovsolutions.com/rest/2/companies/34572/help
The response looks like this:
{
"code": integer,
"message": "string",
"success": boolean,
"method": "string"
"request": "string"
"data": {
"totalItems": integer,
"items": [
{
"identity": {
"userId": "string",
"loginLevel": "string",
"roles": [
"string"
...
]
},
"verbs": [
"string",
...
],
"fields": {
"string": {
"type": "string",
"required": boolean,
"readOnly": boolean,
"values": [
"string",
...
]
},
...
},
"links": {
"string": "string",
...
}
}
]
}
}
Property | Description |
---|---|
code | HTTP status code as an integer. |
message | String to explain the status code. |
success | Boolean to indicate if the request was successful or encountered an error. |
method | The HTTP verb used for the request. |
request | The original request sent to the server. This only includes the URI and the query parameters; it does not include POST data. |
data | The main data structure containing the intended result of the request. |
data.totalItems | The total number of results returned in the response. |
data.items[] | An array of objects that represent the data itself. The array will have one or more records. The array will not be empty; an error will be returned instead. |
data.items[#].identity | Information about user rights. |
data.items[#].verbs | Verbs permitted for this resource in the current user context. |
data.items[#].fields | Field description objects indexed by field name. The properties returned for each field depend on the specific field. A values property will include all the permitted values for the field as a simple array, an indexed array, or a more complex object as needed. |
data.items[#].links | Links available for this resource along with a URI template. |
The API will always return a standard HTTP response code (code) and brief description (message). The following HTTP status codes are currently in use.
Code | Description |
---|---|
200 OK | Success! The included message may provide additional details. |
201 Created | The request has been fulfilled and resulted in a new resource being created. A Location header will be returned with the URI to each newly created resource. |
207 Multi-Status | The overall request was successful, however, there were multiple objects to process and there is a mixture of status codes (possibly successes and failures) to review. |
304 Not Modified | The request was successful, but nothing changed. |
400 Bad Request | The request was invalid. An accompanying error message will explain why, but this will generally be used when a resource is requested without the necessary parameters. |
401 Unauthorized | Authentication credentials were missing or incorrect. |
403 Forbidden | The request is understood, but it has been refused, generally due to authorization failure. |
404 Not Found | The URI requested is invalid or does not exist. |
405 Method Not Allowed | The requested HTTP method is not supported by the resource. |
406 Not Acceptable | The resource does not support any of the requested MIME types. |
500 Internal Server Error | Something is broken. This will generally be returned by the web server itself. |
501 Not Implemented | The server either does not recognize the request method, or it lacks the ability to fulfill the request. |
503 Service Unavailable | The servers are up, but not accepting requests. Most likely, the system is down for maintenance. |
API responses can be customized in several ways, including partial representations, nested resource/link expansion, and content type representations.
By default, all properties will be returned for a resource whether it is the primary resource or an expanded link. Clients may optionally request a partial representation to minimize response sizes.
To request a partial representation of the primary resource, add the fields parameter to the query with a comma separated list of all fields to be returned. Note that links are considered a field and will not be returned in a partial representation unless requested. For example, a client may only want company IDs, names and links so they would specify this query parameter: fields=id,name,links.
A field list may be provided for one or more expanded links by enclosing the field list in parenthesis following the link name. For example, to return the username and first name fields when expanding users from the company object, use this parameter: expand=users(username,firstName).
Field lists may be specified for any combination of the primary resource and expanded links; field lists are never required.
Responses will include a links property by default. Each object in the links object will be keyed with a resource name. An individual link object will include an href property at minimum which provides the URI for the related resource. A self link will always be included. The links object is read only.
A client can follow the URI to a related resource or can request that the resource be included with original request via link expansion. Links can be expanded by passing the expand parameter in the request. For example, to include the users with the response from a company resource, add the parameter expand=users to the company request. You may request expansion for multiple links at the same time by separating each resource with a comma, such as expand=users,industries,jurisdictions.
All links other than self links can be expanded.
A client may specify its preferred content type by adding a file extension to the URL or by specifying the desired type in an Accept header. The file extension will take precedence over the header.
JSON is the default content type for all API responses although other content types are supported, per below. All input is required to be JSON. All errors are returned as JSON. JSON can be explicitly requested by adding a .json extension to the URL or by adding application/json to the Accept header.
A CSV file can be downloaded by adding a .csv extension to the URL or by sending an Accept header with a value of text/csv. CSV is supported for all resources. Requesting a CSV file overrides various other settings, including:
- Data is not paged. The entire result set will be returned in one file.
- Links will not be output, and no links will be expanded. CSV output is limited to the resource being queried.
- Requesting a CSV file for a data manipulation operation (i.e. POST) will result in a 406 Not Acceptable error.
- Data profiling will not be performed.
Reports can be generated in a variety of common formats. Reports are not as flexible as CSV exports because the data must be matched to a form factor, such as a piece of paper. The report definitions can be found using the reportDefinitions resource. The output will show which reports are available for which resources, which content types are supported, and may define defaults for field, filter, and sorting parameters.
Downloading a report requires that the report definition ID be passed in the request using the parameter reportDefinitionId. A matching content type must also be specified as a file extension or as an Accept header. Requesting a report download overrides various other settings, including:
- Data is not paged. The entire result set will be returned in one file.
- Links will not be output, and no links will be expanded.
- Requesting a PDF/Word/Excel file for a data manipulation operation (i.e. POST) will result in a 406 Not Acceptable error.
- Data profiling will not be performed.
- Only the fields in the report definition will be output, regardless of the fields being requested in the URL.
- Default sort and filters may be applied but any sorting or filters specified in the request will be honored.
No other Content Types are supported. If an Accept header is not included in a request or is set to allow any content type, JSON will be returned by default. If an Accept header is included and does not specify a content type acceptable for the given resource and method, the API will return 406 Not Acceptable.
Search against a resource by specifying a query with the q parameter. For example, q=mouse Will find all records with the word mouse anywhere in fields that are permitted by search (permitted search fields vary by resource).
To limit the search to specific fields, set the qf parameter to a comma-delimited list of fields to be searched. For example, q=mouse&qf=lastName,email will find mouse only in the lastName and email fields.
Search is performed using “and” logic. Entering two words will produce results where both words, and similar words, are found. The words do not need to be contiguous. Search words are stemmed so that a search for “employee” would also return results for “employ”, “employer”, “employment”, etc. Common stopwords (e.g. a, the, and, or) are removed from the search criteria.
To search for an exact word or phrase, surround the word(s) or phrase(s) in double quotes.
Filter parameters are defined on a per-resource basis. Multiple filter operations are supported with simple modifiers to provide significant flexibilty.
Since commas are used to support “in” filters, any values that include a comma need to be double quoted. Should you need a double quote within the quoted string, use two double quotes.
Type | Querystring | Description |
---|---|---|
Comparison Filter | lastName=Mouse | Filter parameters are named in accordance with the properties of the returned object. In other words, to filter on the firstName property, pass firstName and your search criteria in the query string. This example will find records where the last name exactly matches Mouse. |
In Filter | firstName=Micky,Minnie,Donald | A comma-delimited list will perform an “in” filter on a field. The example filter will find all records that have the first name Mickey or Minnie or Donald. The parameters of the “in” filter may be scaler values, filter constants, or range filters. |
Range Filter | age=25|35 | A pipe (|) may be used as a range operator to find records with values between the start and end of the range. The example Would find records with an age anywhere between 25 and 35, inclusive of the start and end values. The start and end parameters must be date values or numeric values. |
Multiple Filters | firstName=Mickey&lastName=Mouse | Multiple filters will be combined using “and” logic. This filter will find only those records with the first name Mickey and the last name Mouse. |
Wildcard Modifier | firstName=Jo* | An asterisk (*) may be used as a wildcard character. You may use one or more wildcards anywhere in the search string. This example will find records with the first name Jo, John, Jonathan, Joseph, etc. Wildcards may be used with any filter except for Range Filters. Wildcards should only be used with string fields. A literal asterisk can be represented using the escape sequence \*. |
Not Modifier | username=!*@example.com |
Prefix a filter with a bang (!) to negate the filter. This example will find all usernames that are not at the example.com domain. You cannot negate individual terms of a Range Filter or In Filter, but you can negate the entire filter (i.e. “not between” and “not in”). This modifier is not compatible with the Less Than, Greater Than, or similar modifiers. |
Less Than Modifier | age=<21 | Prefix a filter with < to perform a less than comparison. This example will find all records where age is less than 21. This prefix may only be used to compare against a single value; it cannot be used with Range Filters or In Filters. Furthermore, this modifier should only be used with date values and numeric values. |
Less Than or Equal Modifier | age=<=21 | Prefix a filter with <= to perform a less than or equal comparison. This example will find all records where the age is less than or equal to 21. Usage restrictions are the same as the Less Than modifier. |
Greater Than Modifier | age=>21 | Prefix a filter with > to perform a greater than comparison. This example will find all records where age is greater than 21. Usage restrictions are the same as the Less Than modifier. |
Greater Than or Equal Modifier | age=>=21 | Prefix a filter with >= to perform a greater than comparison. This example will find all records where age is greater than or equal to 21. Usage restrictions are the same as the Less Than modifier. |
Null Constant | {null} | Use {null} in place of a scalar value to perform a null comparison. |
Not Null Constant | {!null} | Use {!null} in place of a scalar value to perform a not null comparison. |
To sort the items in a response, add the sort parameter to the query string followed by a list of property names separated by commas. For example, to sort on company name and then last name, the query parameter would be sort=company,lastName.
To control the direction of the sort, add :a for ascending or :d for descending. To sort the results in descending order by company name, the query parameter looks like sort=company:d,lastName. This is equivalent to sort=company:d,lastName:a.
Paging is controlled by two query parameters. Additionally, each Read Response will include a paging object with links to nearby pages.
Parameter | Description |
---|---|
itemsPerPage | An integer specifying the number of items to return in a single page of data. The default is 200 and the maximum is 1000. |
pageIndex | The page number to return. The first page number is 1. If not specified, the first page is returned. |