Skip to content

Concepts

General Documentation Information

Data Types

The api is written in C#, and as a result the data types in the documentation refer to C# data types. These map cleanly to similar types in other languages and generally do not need expanded upon. The only exception is the ? operator. This indicates a value may be null. So for example, if a data type is specified as bool? that indicates that the value may be null, and if it is not, then the type will be a bool. This also indicates that the api will accept a null in this field.

API Access Keys

The Vendor API uses AWS api keys to control access to the api and to manage rate limiting. If you do not have a token, email us!. To use your key all your requests MUST include the header x-api-key: your-aws-api-key. We have a route to help you test that this is setup properly, see the API key test route for more information.

If you do not have an API key, perform the following:

  1. Create one or more User(s) within the Organization that requires API access. a. We suggest api@organizationName.com for the login email. b. Set a strong password - the password for this user will be used in conjunction with an organization specific API key to authenticate against the API.
  2. Contact api-request@vendnovation.com and provide your Organization Name and the login email(s) of those users you wish to enable API access for.
  3. VendNovation will enable API access for those Users and send you your Organization specific API Key.

Usage Plan Details

All new API access keys are limited to the following restrictions:

Limits
Rate 20 requests per second
Burst 100 requests
Quota 5,000 requests per day

Proper call optimization should allow you to stay within the limits. Remember that all calls support retrieving multiple data sets by ID simultaneously.

API Stages

The Vendor API has multiple deployments you can access. It is recommended you use the most current version of the API. The stages available currently are:

Stage Description
rc An early access deployment of the next release. Code deployed to this stage can be expected to work. If the release contains breaking changes, those changes will generally be posted here one month before full deployment. Non-breaking changes may be posted closer to the full deployment date.
v1 The original production release of the api.
v2 A large rewrite featuring standardized request bodies and an enhanced feature set features. Highlights are templating and role/rights support.
v2.1 A large non-breaking enhancement of v2. Additions include session management and support for uploading files and linking them to various records.

It is our goal to have the APIs exist in perpetuity, even when they are no longer receiving bugfixes. However, should a security-related issue be discovered that cannot be fixed in a non-breaking way, you will be given as much time as possible to migrate to a newer, secure version of the API.

Data Retrieval and Filters

{
  "requestFilter": {
    "organizationIds": [1],
    "siteIds": [1, 4, 6]
  }
}

The Vendor API is not structured like a standard REST API (parent-resource/{parent-resource-id}/child-resource) and is instead built around bulk operations and achieving as much as possible in a single request while still having resource driven routes. To support this goal, api urls are flat. Even though accounts are a logical child resource of organizations, they are accessed at <base-url>/accounts. As the change in URL structure would imply, you are able to retrieve accounts from multiple parent organizations at the same time. The default behavior of the API is to send you all the data about the specified resource type that you have access to. So if I have access to two organizations, and I call GET /machines, the api will return a result set of every single machine in both organizations at once.

As this is often too broad for a given use case, the API is filter driven. Almost every request accepts the standard request filter (found here) and supports multiple filters at the same time. In addition to the standard request filter, some route specific filters are also available and links to them will be found in the routes where applicable. Returning to our machines example, It could be narrowed down to only just the machines at any of the specified sites that also belong to a specific organization (see the example to the right). To get a single (or a few specific machines) you would only specify machineIdentifiers. These principles apply to all routes in the API.

It is worth noting that not only retrieval is a bulk action. Every call in the api supports bulk actions across multiple tiers of parent resources. All bulk actions are treated as atomic sets, so if one element in your action fails, the entire set will be rolled back to it's initial state, and you will be notified of such, with as helpful an error message as can be provided.

DateTime Handling

Unless otherwise stated, all DateTimes are in UTC.

A Note on Time Zones

When working with DateTime filters, there are additional considerations regarding timezones. The DateTimes in our systems are stored in the local time as configured for the site/machine. The stored time for things like transactions report is the local time reported by the machine. As a result, to make working with DateTimes easier if you are not using the website for data tracking, you may consider configure your sites to be UTC.

StartDate and EndDate Clamping

When you provide a StartDate and/or EndDate in your request filter, the dates you provided will not necessarily be the dates used in your request. We apply a series of clamping rules to your DateTimes to restrict your maximum search range to no more than the maximum range (which varies between calls as performance allows) as well as generate either or both DateTimes if they were not both provided. The maximum search range varies from route to route so please refer to the individual route documentation for this info.

Here is a breakdown of this to help you understand how this works

StartDate Provided EndDate Provided Result
Yes Yes Your end date will be modified if the time span between provided start and end is larger than the maximum range
Yes No Your end date will be set to maximum range number of days from your start date
No Yes The start date will be generated as your end date minus range maximum
No No End date will be generated as DateTime.Now, and your start date will be range maximum days earlier

When applicable, the API response will include additional headers to help you detect when we have modified date-time search parameters.

  • search-range-start-date - will contain the modified search start date and time, if applicable.
  • search-range-end-date - will contain the modified search end date and time, if applicable.

Also of note, the time portion of the DateTime is optional. If omitted, StartDate will be given a time of 00:00:00 and EndDate will be given a time of 23:59:59.

Pagination

Paging is universally supported for get requestsin the API. Page parameters are specified by headers.

Header Default Value Meaning
page 1 Which page of results are you requesting.
size 50 How many results per page would you like to retrieve. Will be clamped to 2000 if set higher.

The response's headers will include the paging information we used while processing the request as well as the total number of pages available to be retrieved.

Header Name Meaning
page The page of data returned by the API.
size The page size the api used while processing your request
total-pages How many pages of data are available to be retrieved.

Standardized Request Body

{
    "requestFilter": {
      // Request filter values, if any, go here.
    },
    "routeFilter": {
      // Route filter values, if any, go here.
    },
    "body": {
        //Your data, if any, goes here. For updates and creates this is an array of objects, not a single object
    }
}

Requests made to the api have standardized JSON keys to ensure uniformity of interaction with the API.

  • The request filter is to be assigned to a key named requestFilter.
  • Any route specific filter is to be assigned to a key named routeFilter.
  • Any data models you provide to the api (eg for creates or updates) is to be assigned to a key named body.

To simplify making requests, you can put this in every request body (sans comments) and add data on an as needed basis.

Error Handling

{
  "code": "DATA_ACCESS", // programatically useful error code
  "message": "You tried to update one or more sites outside of your organization. No changes have been made.", // human friendly error message
  "pointers": [1, 4, 7], // an identifier used to find the problem records in your payload
  "pointerName": "Site.Id" // a string that tells you what field the pointers represent
}

When the api encounters an error, it will send back a list of error objects like the one seen in the sidebar. These objects should make it easy to programmatically detect and adjust for errors. Below is a table documenting these common error codes. If a route can have other errors not found in this table a similar table will be found in that route's documentation.

HTTP Code Error Code Definition
401 API_TOKEN Your api token was not present or has expired. Call /authenticate to get one.
403 NO_API_ACCESS You do not have api access. Please contact vendnovation.
500 ACCESS_ERROR Something went wrong while trying to retrieve your data access permissions.
403 DATA_ACCESS An operation was requested for resources outside of your organizations.
500 UNKNOWN_ERROR Something went wrong that may be a problem on our end. Reach out to vendnovation support.
400 GENERIC_ERROR We encountered an error processing your request.
400 UNEXPECTED_RESULT_COUNT Fewer rows were affected by your request than expected, changes may have been made elsewhere.
404 MISSING_RECORD One or more of the specified records could not be found.
421 MISSING_REQUIRED_DATA Your request was serializable but was missing some data required by the business logic. Please refer to the documentation.
400 DESERIALIZATION_ERROR One of your fields could not be deserialized to the correct type.
400 INVALID_DATE_RANGE Your date range's start date was after its end date.
400 DATE_PARSING One or more of your dates was unparseable.