1. Overview
The IDEXX Data Services Batch API provides OData V4 compliant APIs for accessing the major data types collected from practices. See http://www.odata.org/ for more information about OData. The API supports $top, $skip, and $filter. Arithmetic operators and functions are not supported in $filter. The results are limited to 100-20000 entities depending on the entity so $top and $skip must be used to retrieve large datasets.
The API is secured using an OAuth 2 bearer token in JWT format.
The IDEXX Data Services Real-Time API provides immediate (less than 150 ms latency typical) access to REST resources that are task specific. The JSON objects returned by the real-time API can be simple or complex object graphs and contain the data pertinent to the specific use-case or task enabled by the resource.
The real-time API is secured by a JWT that is obtained through the batch API.
2. Documentation
A Swagger UI has been generated for both the Real-time and Batch API’s. View that here.
3. Transport
All communication with the IDEXX Data Services API must be made over SSL (HTTPS) only.
4. Authentication
The IDEXX Data Services API requires authentication. IDEXX Data Services uses a combination of OAuth2 and tokenized URLs for authentication and authorization. Most of the API is accessed using access tokens. Large files can be downloaded using tokenized URLs that expire after a short period of time. The tokenized URLs are generated through the API using valid access tokens.
You use your Username and Password to get access tokens using the IDEXX Data Services API Token API.
4.1. Token Endpoint
Send a POST request to https://dataservices.idexx.com/pims-rt/v1/token
4.1.1. Parameters
4.1.2. Response
The response will be in the form of JSON:
\{
"access_token":"pl0okm9ijn8uhb7yfdftfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJKLpl0okm9ij n8usb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxadfdcf4rfgv5tgb6yhn7ujm8ijFGHJKLpl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJfdepl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJKLpl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJKL",
"token_type":"Bearer"
}
4.1.3. Using the access token
The access token allows you to make requests to the API. The token is passed in the Authorization header.
Authorization: Bearer pl0okm9ijn8uhb7yfdftfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJKLpl0ok m 9ijn8usb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxadfdcf4rfgv5tgb6yhn7ujm8ijFGHJKLpl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJfdepl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJKLpl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1qasz2wsdxc3edcf4rfgv5tgb6yhn7ujm8ijFGHJKL
5. Querying Resources
Certain resources support querying and filtering per the OData specification. Querying requires careful consideration of the request URI. The following sections describe query options and demonstrate some common scenarios.
5.1. Query Syntax
To return all of the entities for a given resource, perform a GET operation on the resource, as described in the resource documentation. The number of entities returned for a single request may be limited, if the query exceeds the maximum number of entities or exceeds the timeout interval. The results are paginated as described in Constructing Filter Strings
When constructing a filter string, keep these rules in mind:
-
Use the logical operators defined by the OData Protocol Specification to compare a property to a value. Note that it is not possible to compare a property to a dynamic value; one side of the expression must be a constant.
-
The property name, operator, and constant value must be separated by URL-encoded spaces. A space is URL-encoded as %20.
-
All parts of the filter string are case-sensitive.
-
The constant value must be of the same data type as the property in order for the filter to return valid results.
5.1.1. Filtering on String Properties
When filtering on string properties, enclose the string constant in single quotes.
The following example filters on the LastName and FirstName property:
5.1.2. Filtering in Numeric Properties
To filter on an integer or floating-point number, specify the constant value on the URI without quotes.
This example returns all entities with an Age property whose value is greater than 30:
This example returns all entities with an AmountDue property whose value is less than or equal to 100.25:
5.1.3. Filtering on Boolean Properties
To filter on a Boolean value, specify true or false without quotes.
The following example returns all entities where the IsActive property is set to true:
5.1.4. Filtering on DateTime Properties
To filter on a DateTime value, specify the datetime keyword on the URI, followed by the date/time constant in single quotes. The date/time constant must be in combined UTC format, as described in Formatting DateTime Property Values.
The following example returns entities where the DateAdded property is equal to July 10, 2008:
5.1.5. Filtering on GUID Properties
To filter on a GUID value, specify the guid keyword on the URI, followed by the guid constant in single quotes.
The following example returns entities where the GuidValue property is equal to a455c695-df98-5678-aaaa-81d3367e5a34:
Pagination. The basic URI for addressing the Tables resource is as follows:
To return all entities for a resource, specify the resource without a filter.
5.2. Query Options
The following query options are supported. You can use these options to limit the set of entities, or entity properties returned by a query.
*Note*
A request that returns more than the default maximum or specified maximum number of results returns a continuation token for performing pagination. When making subsequent requests that include continuation tokens, be sure to pass the original URI on the request. For example, if you have specified a $filter or $top query option as part of the original request, you will want to include that option on subsequent requests. Otherwise your subsequent requests may return unexpected results. See Constructing Filter Strings
When constructing a filter string, keep these rules in mind:
-
Use the logical operators defined by the OData Protocol Specification to compare a property to a value. Note that it is not possible to compare a property to a dynamic value; one side of the expression must be a constant.
-
The property name, operator, and constant value must be separated by URL-encoded spaces. A space is URL-encoded as %20.
-
All parts of the filter string are case-sensitive.
-
The constant value must be of the same data type as the property in order for the filter to return valid results.
5.2.1. Filtering on String Properties
When filtering on string properties, enclose the string constant in single quotes.
The following example filters on the LastName and FirstName property:
5.2.2. Filtering on Numeric Properties
To filter on an integer or floating-point number, specify the constant value on the URI without quotes.
This example returns all entities with an Age property whose value is greater than 30:
This example returns all entities with an AmountDue property whose value is less than or equal to 100.25:
5.2.3. Filtering on Boolean Properties
To filter on a Boolean value, specify true or false without quotes.
The following example returns all entities where the IsActive property is set to true:
5.2.4. Filtering on DateTime Properties
To filter on a DateTime value, specify the datetime keyword on the URI, followed by the date/time constant in single quotes. The date/time constant must be in combined UTC format, as described in Formatting DateTime Property Values.
The following example returns entities where the DateAdded property is equal to July 10, 2008:
5.2.5. Filtering on GUID Properties
To filter on a GUID value, specify the guid keyword on the URI, followed by the guid constant in single quotes.
The following example returns entities where the GuidValue property is equal to a455c695-df98-5678-aaaa-81d3367e5a34:
Pagination for additional information.
Note that the $top query option in the case where results are paginated specifies the maximum number of results per page, not the maximum number of results in the whole response set.
5.3. Supported Comparison Operators
Within a $filter clause, you can use comparison operators to specify the criteria against which to filter the query results. For all property types, the following comparison operators are supported:
Query Option |
URI Expression |
---|---|
Equal |
eq |
Greater Than |
gt |
Greater Than or Equal |
ge |
Less Than |
lt |
Less Than or Equal |
le |
Not Equal |
ne |
Additionally, the following operators are supported for Boolean properties:
Operator |
URI Expression |
---|---|
And |
and |
Not |
not |
Or |
or |
5.4. Query String Encoding
The following characters must be encoded if they are to be used in a query string:
-
Forward slash (/)
-
Question mark (?)
-
Colon (:)
-
'At' symbol (@)
-
Ampersand (&)
-
Equals sign (=)
-
Plus sign (+)
-
Comma (,)
-
Dollar sign ($)
5.5. Sample Query Expressions
The following samples show how to construct the request URI for some typical entity queries using REST syntax.
5.5.1. Returning the Top n Entities
To return the top _n_ entities for any query, specify the *$top* query option. The following example returns the top 10 entities from Clients:
5.5.2. Constructing Filter Strings
When constructing a filter string, keep these rules in mind:
-
Use the logical operators defined by the http://www.odata.org/[OData Protocol Specification] to compare a property to a value. Note that it is not possible to compare a property to a dynamic value; one side of the expression must be a constant.
-
The property name, operator, and constant value must be separated by URL-encoded spaces. A space is URL-encoded as %20.
-
All parts of the filter string are case-sensitive.
-
The constant value must be of the same data type as the property in order for the filter to return valid results.
5.5.3. Filtering on String Properties
When filtering on string properties, enclose the string constant in single quotes.
The following example filters on the *LastName* and *FirstName* property:
5.5.4. Filtering in Numeric Properties
To filter on an integer or floating-point number, specify the constant value on the URI without quotes.
This example returns all entities with an *Age* property whose value is greater than 30:
This example returns all entities with an *AmountDue* property whose value is less than or equal to 100.25:
5.5.5. Filtering on Boolean Properties
To filter on a Boolean value, specify *true* or *false* without quotes.
The following example returns all entities where the *IsActive* property is set to *true*:
5.5.6. Filtering on DateTime Properties
To filter on a *DateTime* value, specify the *datetime* keyword on the URI, followed by the date/time constant in single quotes. The date/time constant must be in combined UTC format, as described in Formatting DateTime Property Values.
The following example returns entities where the *DateAdded* property is equal to July 10, 2008:
5.5.7. Filtering on GUID Properties
To filter on a GUID value, specify the *guid* keyword on the URI, followed by the guid constant in single quotes.
The following example returns entities where the *GuidValue* property is equal to a455c695-df98-5678-aaaa-81d3367e5a34:
6. Pagination
A query may return a maximum of 1,000 items at one time and may execute for a maximum of five seconds. If the result set contains more than 1,000 items, or if the query did not complete within five seconds, the response includes headers which provide you with continuation tokens to use in order to resume the query at the next item in the result set. Continuation token headers may be returned for a query operations and any operations that return lists of entities.
Note that the total time allotted to the request for scheduling and processing the query is 30 seconds, including the five seconds for query execution.
It is possible for a query to return no results but to still return a continuation header.
The continuation token headers are shown in the following table.
To retrieve the continuation tokens and execute a subsequent query to return the next page of results, first inspect the response headers for continuation tokens. If there are no headers or the header values are *null*, there are no additional entities to return.
*Note*
When making subsequent requests that include continuation tokens, be sure to pass the original URI on the request. For example, if you have specified a $filter or $top query option as part of the original request, you will want to include that option on subsequent requests. Otherwise your subsequent requests may return unexpected results.
Note that the $top query option in this case specifies the maximum number of results per page, not the maximum number of results in the whole response set.
*Note*
The total time allotted to the request for scheduling and processing a query is 30 seconds, including five seconds for query execution.
If the operation is an insert, update, or delete operation, the operation may have succeeded on the server despite an error being returned by the client. This may happen when the client timeout is set to less than 30 seconds, which is the maximum timeout for an insert, update, or delete operation.
6.1. Sample Response Headers and Subsequent Request
The following code example shows a set of sample response headers from an entity query against a Clients that returns a continuation header. The _x-dp-continuation-NextRowKey_ is returned.
Date: Mon, 27 Jun 2016 20:11:08 GMT
Content-Type: application/json;charset=utf-8
Server: DP/1.0 Microsoft-HTTPAPI/2.0
Cache-Control: no-cache
x-dp-request-id: f9b2cd09-4dec-4570-b06d-4fa30179a58e
x-dp-version: 2015-10-10
x-dp-continuation-NextRowKey: 1!8!QmVuOTk5
Content-Length: 880298
The request for the next page of data can be constructed like the following URI:
7. Data Formats
7.1. Formatting DateTime Property Values
DateTime property values must be represented as combined Coordinated Universal Time (UTC) values. The *Timestamp* property, which is an opaque property maintained by the entities, is also represented in this format. UTC formats are described by ISO 8601.
An example of the combined UTC format is as follows. The date is specified first, followed by the literal string "T", which designates the beginning of the time element. The literal string "Z" at the end of the string designates that the time is expressed in UTC:
2009-03-18T04:25:03Z
The following code example shows one way to construct the combined UTC format from the current UTC date using .NET:
string roundtripDateTime = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind);
8. Error Codes
In deference to best practices for REST APIs. IDEXX Data Services returns standard HTTP status codes to report errors. The following table summarize possible errors when making API calls.
Error code | HTTP status code | User message |
---|---|---|
ConditionNotMet |
Not Modified (304) |
The condition specified in the conditional header(s) was not met for a read operation. |
MissingRequiredHeader |
Bad Request (400) |
A required HTTP header was not specified. |
UnsupportedHeader |
Bad Request (400) |
One of the HTTP headers specified in the request is not supported. |
InvalidHeaderValue |
Bad Request (400) |
The value provided for one of the HTTP headers was not in the correct format. |
MissingRequiredQueryParameter |
Bad Request (400) |
A required query parameter was not specified for this request. |
UnsupportedQueryParameter |
Bad Request (400) |
One of the query parameters specified in the request URI is not supported. |
InvalidQueryParameterValue |
Bad Request (400) |
An invalid value was specified for one of the query parameters in the request URI. |
OutOfRangeQueryParameterValue |
Bad Request (400) |
A query parameter specified in the request URI is outside the permissible range. |
RequestUrlFailedToParse |
Bad Request (400) |
The url in the request could not be parsed. |
InvalidUri |
Bad Request (400) |
The requested URI does not represent any resource on the server. |
InvalidHttpVerb |
Bad Request (400) |
The HTTP verb specified was not recognized by the server. |
EmptyMetadataKey |
Bad Request (400) |
The key for one of the metadata key-value pairs is empty. |
OutOfRangeInput |
Bad Request (400) |
One of the request inputs is out of range. |
InvalidAuthenticationInfo |
Bad Request (400) |
The authentication information was not provided in the correct format. Verify the value of _Authorization_ header. |
InvalidInput |
Bad Request (400) |
One of the request inputs is not valid. |
InvalidMetadata |
Bad Request (400) |
The specified metadata is invalid. It includes characters that are not permitted. |
InvalidResourceName |
Bad Request (400) |
The specifed resource name contains invalid characters. |
MetadataTooLarge |
Bad Request (400) |
The size of the specified metadata exceeds the maximum size permitted. |
ConditionHeadersNotSupported |
BadRequest (400) |
Condition headers are not supported. |
MultipleConditionHeadersNotSupported |
Bad Request (400) |
Multiple condition headers are not supported. |
AuthenticationFailed |
Forbidden (403) |
Server failed to authenticate the request. Make sure the value of the _Authorization_ header is formed correctly including the signature. |
InsufficientAccountPermissions |
Forbidden (403) |
Read operations are currently disabled. |
InsufficientAccountPermissions |
Forbidden (403) |
Write operations are not allowed. |
ResourceNotFound |
Not Found (404) |
The specified resource does not exist. |
AccountIsDisabled |
Forbidden (403) |
The specified account is disabled. |
InsufficientAccountPermissions |
Forbidden (403) |
The account being accessed does not have sufficient permissions to execute this operation. |
UnsupportedHttpVerb |
Method Not Allowed (405) |
The resource doesn’t support the specified HTTP verb. |
AccountAlreadyExists |
Conflict (409) |
The specified account already exists. |
AccountBeingCreated |
Conflict (409) |
The specified account is in the process of being created. |
ResourceAlreadyExists |
Conflict (409) |
The specified resource already exists. |
ResourceTypeMismatch |
Conflict (409) |
The specified resource type does not match the type of the existing resource. |
MissingContentLengthHeader |
Length Required (411) |
The _Content-Length_ header was not specified. |
ConditionNotMet |
Precondition Failed (412) |
The condition specified in the conditional header(s) was not met for a write operation. |
RequestBodyTooLarge |
Request Entity Too Large (413) |
The size of the request body exceeds the maximum size permitted. |
InvalidRange |
Requested Range Not Satisfiable (416) |
The range specified is invalid for the current size of the resource. |
InternalError |
Internal Server Error (500) |
The server encountered an internal error. Please retry the request. |
OperationTimedOut |
Internal Server Error (500) |
The operation could not be completed within the permitted time. |
ServerBusy |
Service Unavailable (503) |
The server is currently unable to receive requests. Please retry your request. |