Filtering, Search & Ordering
All list endpoints in the Moloni ON API accept an options argument that lets you filter, search and order results. These work alongside pagination and can be combined freely. This guide uses the products query as an example, but the pattern is the same across all list endpoints.
The options argument
List queries accept an options input with these fields:
query {
products(companyId: 1, options: {
filter: [...]
search: { ... }
order: [...]
pagination: { ... }
}) {
errors { field msg }
data { ... }
options { ... }
}
}
All fields are optional; use only what you need.
Filtering
Filters let you narrow results by exact conditions on specific fields. You pass an array of filter objects, each with a field, a comparison operator, and a value.
Structure
filter: [
{ field: <FilterField>, comparison: <Comparison>, value: <String> }
]
For products, the filter input is ProductFilterOptions, with fields defined in ProductFilterField.
Comparison operators
The Comparison enum provides these operators:
| Operator | Description | Example value |
|---|---|---|
eq | Equal to | "1" |
ne | Not equal to | "0" |
gt | Greater than | "100" |
gte | Greater than or equal | "100" |
lt | Less than | "50" |
lte | Less than or equal | "50" |
like | Contains (partial match) | "CHAIR" |
notLike | Does not contain | "DRAFT" |
in | In a set of values | "[1, 2, 3]" |
notIn | Not in a set of values | "[4, 5]" |
Examples
Filter visible products only:
query {
products(companyId: 1, options: {
filter: [
{ field: visible, comparison: eq, value: "1" }
]
}) {
data { productId name reference }
}
}
Filter products with price ≥ 100 in a specific category:
query {
products(companyId: 1, options: {
filter: [
{ field: price, comparison: gte, value: "100" }
{ field: productCategoryId, comparison: eq, value: "5" }
]
}) {
data { productId name price }
}
}
Multiple filters are combined with AND logic, meaning all conditions must match.
Filter products updated after a specific date:
query {
products(companyId: 1, options: {
filter: [
{ field: updatedAt, comparison: gte, value: "2025-01-01" }
]
}) {
data { productId name }
}
}
Filter by multiple IDs using in:
query {
products(companyId: 1, options: {
filter: [
{ field: type, comparison: in, value: "[1, 2, 3]" }
]
}) {
data { productId name type }
}
}
Filtering on related fields
Some filter fields reference related entities using double-underscore notation. For example, to filter products by supplier:
query {
products(companyId: 1, options: {
filter: [
{ field: suppliers__supplier__supplierId, comparison: eq, value: "42" }
]
}) {
data { productId name }
}
}
Other relational filter fields for products include warehouses__warehouse__warehouseId, taxes__tax__taxId and identifications__text, among others. See ProductFilterField for the full list.
Search
Search performs a partial text match across one or more fields. Unlike filters, search uses a single object (not an array).
Structure
search: { field: <SearchField>, value: <String> }
For products, the search input is ProductSearchOptions, with fields defined in ProductSearchField.
The ALL field
Most endpoints provide a special ALL field that searches across every searchable field at once. This is the most common choice:
query {
products(companyId: 1, options: {
search: { field: ALL, value: "widget" }
}) {
data { productId name reference }
}
}
This searches the product name, reference, price, notes, summary, supplier references, and identification codes simultaneously.
Searching a specific field
To search only within a specific field:
query {
products(companyId: 1, options: {
search: { field: reference, value: "CHAIR-001" }
}) {
data { productId name reference }
}
}
Ordering
Ordering sorts results by one or more fields. You pass an array of order rules, each with a field and a sort direction.
Structure
order: [
{ field: <OrderField>, sort: <Sort> }
]
The Sort enum has two values: ASC (ascending) and DESC (descending).
For products, the order input is ProductOrderOptions, with fields defined in ProductOrderField.
Single field ordering
query {
products(companyId: 1, options: {
order: [{ field: name, sort: ASC }]
}) {
data { productId name }
}
}
Multiple field ordering
When you pass multiple order rules, they are applied in sequence: the first rule is the primary sort, the second breaks ties, and so on:
query {
products(companyId: 1, options: {
order: [
{ field: stock, sort: DESC }
{ field: name, sort: ASC }
]
}) {
data { productId name stock }
}
}
This returns products with stock first (descending), then alphabetically by name within each group.
Combining everything
All options can be used together. Filters and search narrow the result set, ordering sorts it and pagination slices it:
query {
products(companyId: 1, options: {
filter: [
{ field: visible, comparison: eq, value: "1" }
{ field: price, comparison: gte, value: "10" }
]
search: { field: ALL, value: "chair" }
order: [{ field: price, sort: ASC }]
pagination: { page: 1, qty: 20 }
}) {
errors { field msg }
data {
productId
name
reference
price
}
options {
filter { field comparison value }
search { field value }
order { field sort }
pagination { page qty count }
}
}
}
Response:
{
"data": {
"products": {
"errors": [],
"data": [
{ "productId": 88, "name": "Office Chair Basic", "reference": "CHAIR-001", "price": 49.99 },
{ "productId": 102, "name": "Office Chair Pro", "reference": "CHAIR-002", "price": 149.99 }
],
"options": {
"filter": [
{ "field": "visible", "comparison": "eq", "value": "1" },
{ "field": "price", "comparison": "gte", "value": "10" }
],
"search": { "field": "ALL", "value": "chair" },
"order": [{ "field": "price", "sort": "ASC" }],
"pagination": { "page": 1, "qty": 20, "count": 2 }
}
}
}
}
The options object in the response echoes back exactly what was applied, including the pagination.count reflecting the total number of records matching all filters and search, before pagination is applied.
Next steps
- Pagination: Page through filtered and searched result sets
- Error Handling: Understand the error model returned by all operations