API Paging and Query Language
API Paging and Query Language
Developer-friendly cursor paging and a compact query language for filtering, sorting, selecting, and expanding resources via REST. Use these query parameters with your HTTP endpoints; no SDK required.
What you get
- Flexible filter language with short-hand operators and support for spaces/quoting
- Cursor-based pagination with
before/aftersemantics selectfield projection andexpandfor related resources (with per-path selects)sort,limit,or/nor/and- Optional
countTotalflag
How it works
- Compose queries with
filter,select,expand,sort,limit,before,after,countTotal. - All parameters are URL query parameters; examples below use curl.
Quick start (REST)
Request the first page with filters, selection and sorting:
curl -G 'https://api.example.com/customers' \
--data-urlencode 'filter=email:[email protected] createdAt|gtd|2024-01-01T00:00:00.000Z' \
--data-urlencode 'select=id name email' \
--data-urlencode 'sort=-createdAt' \
--data-urlencode 'limit=20' \
--data-urlencode 'countTotal'
Paginate forward using after (pass the last id from the previous page):
curl -G 'https://api.example.com/customers' \
--data-urlencode 'filter=email~doe' \
--data-urlencode 'after=ent_2x9abc' \
--data-urlencode 'limit=20'
HTTP query parameters
limit: number. Default 20.sort: space-separated list. Example:sort=-createdAt publishedAt.select: space-separated fields to include/exclude. Example:select=id name -secret.expand: space-separated population paths; use:to select subfields. Example:expand=user:firstName,email posts:title.filter: space-separated filter expressions (see grammar below).or,nor,and: same syntax asfilter; combined using OR/NOR/AND logic.before: id of the last item from the previous page (cursor backward).after: id of the last item from the current page (cursor forward).countTotal: boolean. Supports short form:&countTotalis treated astrue.
Boolean short form
Short form without value is treated as true, so &countTotal is valid.
Filter language (for REST queries)
The filter query is a space-separated list of entries. Each entry can be written in long or shorthand form.
Operators
| Operator | Long Form | Shorthand(s) | Meaning |
|---|---|---|---|
| eq | field|eq|value | field:value, field=value | Equals |
| ne | field|ne|value | -field:value, field!=value | Not equals |
| gt | field|gt|N | field>N | Greater than |
| gte | field|gte|N | field>=N | Greater than or equal |
| lt | field|lt|N | field<N | Less than |
| lte | field|lte|N | field<=N | Less than or equal |
| like | field|like|text | field~text | Case-insensitive regex match |
| nlike | field|nlike|text | -field~text | Not match (case-insensitive) |
| in | field|in|a,b,c | — | In list |
| nin | field|nin|a,b,c | — | Not in list |
| all | field|all|a,b,c | — | Array contains all values |
| size | field|size|N | — | Array size equals N |
| nsize | field|nsize|N | — | Array size not N |
| exists | field|exists|true | — | Field exists (boolean) |
Numbers are parsed safely; non-numeric values remain strings.
Date operators
For common date fields (e.g., createdAt, updatedAt, txTime, date):
gtd-> greater than date:createdAt|gtd|2020-01-01T00:00:00.000Zgted-> greater than or equal dateltd-> less than datelted-> less than or equal date
Tip: You can also use numeric operators (e.g., createdAt>=2020-01-01T...).
Grouping with OR/NOR/AND
Use separate params to group expressions:
?filter=state:active amount>1000
&or=country:NG country:GH
&nor=channel:manual
&and=verified:true
Each param uses the same space-separated grammar as filter and is converted to $or, $nor, and $and blocks.
Quoting and spaces
- Wrap values with spaces in quotes or angle brackets:
-
name:"John Doe"-name:<John Doe> - Escape
"or>inside quoted/bracketed values with a backslash:name:"John \"JD\" Doe"
Identifier fields
You can filter by identifiers such as id, customer, card, account, program, event, or bin. Nested identifiers are supported using dot notation (e.g., customer.id). Examples:
filter=customer|eq|cus_abc123
filter=customer.id|eq|us_xyz123
filter=account|in|acc_1,acc_2,acc_3
Select and expand
select
- Space-separated list of fields to include/exclude (prefix with
-to exclude). - Depth is limited to 1 by default; deeper paths may be truncated.
Examples:
select=id name -secret source
expand (include related)
- Space-separated paths; use dot-notation for nesting (max depth 2 by default).
- Use
:to specify fields of the populated path:expand=user:firstName,email. - Multiple selects for the same path are merged.
Examples:
expand=user:firstName,email posts:title,createdAt posts.author:firstName
Sorting
Space-separated list; prefix - for descending.
sort=-createdAt -publishedAt
When after is used, results preserve the expected chronological order.
Pagination (cursor semantics)
after=<id>: fetch items after the provided id (forward).before=<id>: fetch items before the provided id (backward).- Default sort is newest first. Default
limitis 20. - Response shape:
{
"data": [
{ "id": "66ef0b3a2f1c0f0d9b3c1a22", "name": "John Doe", "email": "[email protected]" }
],
"metadata": { "hasMore": true, "totalCount": 128 }
}
hasMore is true when the page returns limit items. totalCount is only computed when requested via countTotal.
End-to-end examples
Filters
/customers?filter=email|eq|[email protected] metadata.key|eq|value accountType|in|main,sub,virtual
/customers?filter=email:[email protected] metadata.key:value -accountType:sub
/customers?filter=name:"John Doe" email~john
/customers?filter=name:<John Doe> email~john
/customers?filter=amount|gt|1000 amount|lt|2000
/customers?filter=amount>1000 amount<2000
/customers?filter=amount=2000 fees!=0
/customers?filter=createdAt|gtd|2020-01-01T00:00:00.000Z createdAt|ltd|2020-01-31T23:59:59.999Z
Sorting, selecting, expanding
/logs?filter=method|eq|POST path|eq|/card-programs&select=path method initiator&countTotal=true
/logs?filter=method|eq|POST&select=path method initiator&countTotal
/entities?expand=user:firstName,email timeline.user:firstName
## Errors
Invalid filter format returns HTTP 400:
```json
{
"statusCode": 400,
"message": "Incorrect format for 'filter' parameter."
}
## Notes
- Values with spaces must be quoted: `name:"John Doe"` or `name:<John Doe>`.
- Some deeply nested `expand` paths may be truncated for performance; use `:` to choose fields per relation.
- For equality/not-equality, both `:` and `=`/`!=` are supported (e.g., `state:active`, `amount=2000`, `fees!=0`).