API Design Conventions

To ensure you have the best integration experience possible with our APIs, here are the policies and conventions we follow for designing and updating our APIs, and some overarching guidelines for developers consuming them.

Hostname

The documentation lists URI paths as the identifiers for each API, generally starting with something like /v2/fields. These paths are appended to the hostname, which is:

https://api.awhere.com

Note that only secure connections (i.e., https) are accepted.

Rate Limits

At this time, all API consumers are limited to 1800 requests per minute (or 30 requests per second). Trial accounts are currently limited to half that limit. If you exceed your rate limit, the APIs will return HTTP Status Code 429. In this case, wait a bit and try the request again.

To keep track of your rate limiting thresholds at any given time, you can refer to three HTTP headers that are returned with all API responses:

Header Description
X-RateLimit An integer that notes your total rate limit per period (e.g., 600 per minute). This doesn't change unless you have a different negotiated rate limit.
X-RateLimit-Remaining An integer that notes how many requests you have remaining in the current period.
X-RateLimit-Reset A timestamp noting when the remaining requests will be reset. This timestamp is a Unix timestamp expressed in milliseconds.

Best Practice Suggestions:

  • If you deploy multiple apps using the aWhere APIs, generate a unique credential for each one. Sharing keys can inadvertently lead to triggering the restriction.
  • If you are developing a mobile application where many users will be using it at once from many different locations (that is, not from your central Software as a Service product), contact us to discuss setting up special access.
  • Note that using multi-threading for your API access will allow for more calls at one time, but will also decrease your rate limit thresholds more quickly.

Response Formats

The APIs always return JSON-formatted payloads.

Versioning and API Contracts

We consider the design of our APIs a "contract" with our developer community, where certain changes may be considered "breaking" changes that could potentially break your application. We have designed our next generation platform with very specific guidelines for what constitutes part of the contract versus things that may change without warning. As you write your code, keeping the non-contract things in mind will ensure your app is resilient against any potential changes in the future.

In Contract Not In Contract
All aspects of the URI Path The order of properties in payloads.
Payload property names New properties and query string parameters may be added at any time (i.e., don't validate response schemas)
The existence of defined properties and query string parameters (e.g., properties won't be removed) The default sort order of multiple objects in an array (unless you use the sort parameter).
The availability of a particular response format for a given endpoint (if JSON is available now, it will reman available). The default number of objects in a paginated response.
HTTP Status Codes The existence of or format of a value for any property (values may be null).
The existence of HTTP headers directly related to your processing responses (e.g., Location, Content-Range). Error message text (key off of the status code, not the error message).
Time zones
HTTP Headers related to the transaction (e.g., CORS, Gzip)

If we ever need to release a change that could be breaking, these will normally be released as new versions of the API. When circumstances require we release a breaking change, you'll be given as much notice as possible and we'll make every effort to mitigate the changes required in your code.

Hypermedia (HATEOAS) and Pagination

All of our APIs are built with hypermedia links that describe the context for a particular piece of data. This is a concept in RESTful APIs that essentially means our APIs self-describe how they fit into the big picture. For example, on APIs that return lists of objects, there will be "previous page" and "next page" links indicating there are more results. Likewise, requesting weather data for a field will include a link to the relevant field object, agronomics or modeling APIs may reference the relevant planting information, etc.

Our hypermedia approach follows the Hypertext Application Language (HAL) standard for RESTful APIs.

When an API supports pagination and there are more objects than fit in a single response, the "previous page" and/or "next page" links will be included. Each of these links includes the parameters required to go to the next page, so you can simply use the values as they are provided in your next API call. If there are no more pages in either direction then the link is not included. Also note that not all APIs support pagination, for those that do the documentation will detail how to move between pages.

Sorting

Some APIs that return many objects of the same type will support sorting those objects by one of the properties. The documentation for each API will specify which properties are sortable, and the sort always happens with a query string parameter named sort, like so:

?sort=date

You can sort by multiple properties by concatening property names with a comma. Sorts can happen in either ascending or descending order. Ascending is the default, to sort in descending order insert a minus sign () before the property name. In the following example, the results are sorted by lastname A-Z, and records with the same last name are sorted by firstname Z-A:

?sort=lastname,-firstname

Flexible Payloads

Most of our APIs support flexible payloads by requesting only the properties you need from the API. For example, by default the weather observations API includes temperatures, precipitation, solar energy, wind, and relative humidity. If your application only uses temperatures and precipitation, you can request that only those properties be returned, reducing the overall size of the payload and related bandwidth and speed.

Each API defines the properties that can be selected, and some have properties that are always included (like hypermedia links). To select only the properties you want, you'll use a query string parameters called properties, for example:

?properties=temperatures,precipitation

When this parameter is not used, all properties are returned by default.

HTTP Status Codes and Headers

We use the standard set of HTTP status codes to communicate about the success or failure of an API call. We also use error messages, but over time the error messages can be refined or altered. As noted above, the status codes are considered part of the contract, and we'll always return the same status code for a given error condition, even if the error message changes in the future.

Some of the standard status codes we use include:

Code Label Meaning
200 OK The request completed successfully.
201 Created Returned when something is successfully created.
204 No Content Returned when something is successfully deleted.
400 Bad Request This means there is a mistake in the way you wrote your API request. Maybe a parameter is missing or the URI format couldn't be deciphered.
401 Unauthorized This means we couldn't authenticate your request. Be sure you generated and included an Access Token in your request, or that it hasn't expired.
403 Forbidden This means you aren't allowed to access the data you requested. Maybe it's outside your geographic area or you haven't subscribed to that set of APIs.
404 Not Found We use this to mean we don't have the requested data, for example maybe the location doesn't exist or we don't have the requested data for the requested location.
405 Method Not Allowed Not all APIs support all HTTP verbs, and if you accidentally use a verb that isn't supported by the API, our system will let you know that with this error code.
416 Requested Range Not Satisfiable We use this code when you request more pages than exist, for example if you have 100 results across two pages, and request objects 101-125, we'll send back this error code. You can prevent it by referencing the Content-Range header and pagination links.
429 Too Many Requests If you send way too many API calls at once (see Rate Limits), then we'll temporarily return this error code asking you to slow down your rate of requests. You might also consider the batch job system to more efficiently make many requests at once.
500, 502, 503 Various A 5XX code means something has gone wrong on our side. At this point, alarm bells start going off and our teams are likely already looking at the problem. Try your request again shortly.

In addition to HTTP status codes, we also use a variety of standard HTTP headers to communicate meta information about your request, and you use them to do the same about data you're sending us. Here are some of the standard HTTP headers our system will send:

Header Where Description
Authorization Request You'll send your Access Token in this header so we can authorize your request.
Content-Type Request & Response Describes the format of the data being sent. For now it will always be application/json.
X-RateLimit
X-RateLimit-Remaining
X-RateLimit-Reset
Response These headers describe how you're performing with your rate limit quota, as described above.
Access-Control-Allow-Headers
Access-Control-Allow-Methods
Access-Control-Allow-Origin
Access-Control-Max-Age
Response These are CORS headers, which instruct a web browser that your web application is allowed to use the APIs directly from JavaScript. See Browser-Based API Calls below.
Content-Range Response This header is sent back with API responses that contain lists of objects. Further detail is described in the documentation for each API that uses this header.
Location Response When you create something, this header is returned with the URI for that newly created object. For convenience, most of our APIs also returned the created object, but you can also save this value to reference it by URI.

Error Messages

Whenever our APIs throw an error, you can expect that we'll always use the same HTTP Status Code (see above) for any given type of of error condition. Additionally, we attempt to return additional information or advice whenever possible to guide you toward fixing the problem. When an error is triggered, the API will return a payload body formatted like so:

{
"statusCode": {code},
"statusName":"{status}",
"errorId":"{errorId}",
"simpleMessage":"{simpleMessage}",
"detailedMessage":"{detailedMessage}"
}
Placeholder Description
{code}
and
{status}
This echoes the HTTP status code and corresponding label / name that the API returned.
{errorId} This is an internal error ID that can help aWhere support staff trace peculiar problems in our logs.
{simpleMessage} This is a simple error message that can often be displayed in your application.
{detailedMessage} A more detailed error message designed for developers, this usually includes more detail about the problem with advice on how to fix the problem. We'd suggest not displaying this message to your users, it's really intended for your use.

Browser-Based API Calls

The APIs support Cross-Origin Resource Sharing (CORS) for compatible browsers, enabling the option to make API calls directly from JavaScript code executed in a web browser. Most of our APIs support CORS, except for the Authentication and Batch Jobs systems.

When implementing this kind of architecture, you cannot generate your OAuth2 Access Token in the browser. Generating the token requires your API Key and Secret; because JavaScript in a browser is inherently insecure, someone could extract your credentials from it even if you minify or obscure the code. Read the Making API Calls From a Browser-based Application Guide for more information on how to implement a secure, browser-based API client.

Deprecation Policy

From time to time it is necessary to remove an API or system from service. If we intend to discontinue an API or make backward-incompatible changes, we will provide at least 3 months notice prior to deprecation. After deprecation, the API will no longer be supported:

  • Documentation will be removed.
  • Failures of the API may not be fixed.
  • The API may be taken offline at any time.

When an API is scheduled for deprecation, we will announce it in the Announcements areas of this website and on the relevant documentation.

In some cases, APIs may need to be removed from service sooner than 3 months if required by law, or if the API creates a security risk or substantial economic or technical burden that cannot be resolved (as determined by aWhere's reasonable good faith judgment). These would be extreme circumstances and our goal will always be to provide as much notification as possible.