AAkilIQ
Get an API key

Reference

Filtering, sorting and paging

Every read is a Query Specification: a JSON object sent as the q parameter of the rows endpoint, or as the body of the query endpoint.

The Query Specification

{
  "select": ["reference", "title", "country", "published_on"],
  "filters": [
    { "field": "country", "operator": "in", "value": ["KE", "UG"] },
    { "field": "published_on", "operator": "gte", "value": "now-30d" },
    { "field": "estimated_value", "operator": "lt", "value": 100000 }
  ],
  "search": { "query": "medical equipment", "fields": ["title"] },
  "sort": [{ "field": "published_on", "direction": "desc" }],
  "limit": 50
}
MemberMeaning
selectThe fields to return. Left out, every field you may read.
filtersConditions every row must meet, each a field, an operator and a value.
searchWords to find in the fields the publisher made searchable.
sortThe order, by fields the publisher made sortable, ascending or descending.
limitHow many rows a page holds, up to the dataset's maximum.
cursorWhere the next page starts: the next_cursor of the page before.
offsetRows to skip. Capped, because a deep offset reads what it skips: prefer the cursor.

Every member is optional. An empty specification is the first page of every field you may read, in the dataset's own order.

Filter operators

OperatorMatches rows whose field is
eqEqual to the value.
neqNot equal to the value.
gtGreater than the value.
gteGreater than or equal to the value.
ltLess than the value.
lteLess than or equal to the value.
containsText containing the value.
starts_withText starting with the value.
ends_withText ending with the value.
inEqual to one of the values in a list.
not_inEqual to none of the values in a list.
is_nullHas no value; the filter takes no value.
is_not_nullHas a value; the filter takes no value.
matchesText matching the regular expression given as the value.

Filters combine with AND. A range is two filters on one field, such as gte and lt.

Values

A value's JSON type must suit the field: a string for text, a whole number for an integer, a number for a decimal, true or false for a boolean.

A date is written YYYY-MM-DD. A time is written YYYY-MM-DDTHH:MM:SS, with up to six decimal places of a second; a time with a zone ends in Z or ±HH:MM and is compared in UTC.

A date, or a time with a zone, can be relative to the request: now, or now plus or minus minutes, hours, days or weeks, such as now-7d.

Values are always sent as data, never as part of a statement, whatever they contain.

What the publisher allows

The dataset's publisher decides which fields can be read, filtered, sorted and searched, and with which operators.

A specification that asks for anything else is refused with 400 and the code query_invalid. The details list every reason at once, each with one of these codes.

unknown_fieldfield_not_returnablefield_not_filterablefield_not_sortablefield_not_searchableoperator_not_permittedvalue_requiredvalue_not_permittedvalue_must_be_listvalue_must_not_be_listlimit_exceededsearch_not_supporteddataset_mismatchvalue_type_mismatchlimit_invalidoffset_invalidoffset_exceededpagination_conflictcursor_invalidsort_direction_invalidcost_exceeded

Paging

A page holds limit rows, or the dataset's default. While more rows follow, the page carries next_cursor: send it back as cursor, with the same filters and sort.

A cursor is sealed. It cannot be read or built, and a changed one is refused.

Conditional requests

Every page has an ETag. Send it back in If-None-Match when you read rows with GET: a page that has not changed is answered 304, with no body, for a tenth of the credits.

A query sent with POST is not answered 304: a matching If-None-Match there is answered 412 with the code precondition_failed.