This page explains how to use the filter query parameter to retrieve only the records you need from list endpoints in the Kanbert REST API. It’s written for external developers integrating with the API and is safe to use with Redocly.
- Add a
filterquery parameter to list endpoints (e.g.,GET /api/v1/projects). - Two formats are supported: JSON and a human‑readable string DSL.
- You can combine multiple conditions, nest groups with
and/or, and use rich operators (e.g.,contains,in,gte). - Fields and operators are validated per endpoint. Unknown fields/operators return a 400 error.
Filtering is supported on list endpoints (for example, GET /api/v1/projects). Consult each endpoint’s description to see a list of filterable fields and their types. In general, you can expect common fields like id, created_at, and domain‑specific fields to be available.
Field availability is endpoint‑specific. When in doubt, try the examples below or check the endpoint’s filter Query parameter.
You can pass the filter parameter in one of two formats:
Simple array (logical AND by default):
[
{"field": "title", "op": "contains", "value": "Acme"},
{"field": "created_at", "op": "gte", "value": "2024-01-01"}
]Explicit boolean grouping with and/or:
{
"and": [
{"field": "client.name", "op": "contains", "value": "Acme"},
{"or": [
{"field": "shortcode", "op": "eq", "value": "P-42"},
{"field": "shortcode", "op": "startswith", "value": "P-"}
]}
]
}Form‑encoded equivalent is also supported (useful for HTML forms):
filter[0][field]=title&filter[0][op]=contains&filter[0][value]=AcmePass a readable string instead of JSON:
filter=title contains "Acme" and (created_at >= "2024-01-01" or client.name contains 'Corp')Examples:
filter=shortcode = "P-42"
filter=client.name contains 'Acme' or title startsWith 'P-'
filter=status in ['ACTIVE','PENDING'] and budget >= 1000
filter=primary_contact_id is nullUnless restricted by the endpoint, the following operators are generally available:
- Comparison:
eq,ne/neq,lt,lte/le,gt,gte/ge - Strings:
contains,like,startsWith,endsWith - Sets:
in,nin/notin(arrays like[1,2,3]or['A','B']) - Null checks:
is null,is not null
Operator names are case‑insensitive in the DSL format. Symbol equivalents are supported in DSL too: =, !=, <, <=, >, >=.
Filters are type‑aware. Common types include:
string— free‑text fields; use string operators likecontainsor equality.number— numeric fields; use comparison operators.boolean—true/falsevalues.datetime/date— ISO‑8601 timestamps or dates, e.g.,2025-01-31T12:34:56Zor2025-01-31.enum— limited set of string values; combine witheqorin.id— Entity ID. Usually Schema of entity is mentioned at filter definition.relation- Can be used to filter a N+1 relation. See Section "Relation filters" below
If a field maps to a related model, dot‑notation may be available (e.g., client.name).
You can filter by conditions on relations using relation operators and counts.
- any: at least one related record matches the sub‑filter. If no sub‑filter is provided, it means “has at least one related record”.
- none: no related records match the sub‑filter. Without a sub‑filter, it means “has no related records”.
- all: every related record matches the sub‑filter (use when all associated rows must meet a condition).
- .count: compare the number of related records using standard comparison operators (
=, !=, <, <=, >, >=).
Examples (DSL):
# Any related member with first_name = 'Neil'
filter=members any (first_name = 'Neil')
# Has at least one member (existence)
filter=members any
# No related members with role = 'EXTERNAL'
filter=members none (role = 'EXTERNAL')
# All related tasks are completed
filter=tasks all (status = 'DONE')
# Projects with more than 0 tasks
filter=tasks.count > 0
# Projects with at least 3 active tasks
filter=tasks.count >= 3 and tasks any (status = 'ACTIVE')Examples (JSON):
[
{"field":"members","op":"any","value":{"field":"first_name","op":"eq","value":"Neil"}},
{"field":"members","op":"none","value":{"field":"role","op":"eq","value":"EXTERNAL"}},
{"field":"tasks","op":"all","value":{"field":"status","op":"eq","value":"DONE"}},
{"field":"tasks.count","op":"gt","value":0},
{"field":"tasks.count","op":"gte","value":3}
]Notes:
- The sub‑filter for
any,none, andalluses the same field/operator rules as top‑level filters, but fields are relative to the related model (e.g.,members.first_name). - You can also combine relation filters with other conditions and boolean groups.
Below are example requests using cURL. Replace the base URL and endpoint as needed.
Filter by title substring and minimum creation date (JSON):
curl -G \
--data-urlencode 'filter=[{"field":"title","op":"contains","value":"Acme"},{"field":"created_at","op":"gte","value":"2024-01-01"}]' \
'https://api.kanbert.com/api/v1/projects'Find by related client name or matching shortcode prefix (JSON with grouping):
curl -G \
--data-urlencode 'filter={"and":[{"field":"client.name","op":"contains","value":"Acme"},{"or":[{"field":"shortcode","op":"eq","value":"P-42"},{"field":"shortcode","op":"startsWith","value":"P-"}]}]}' \
'https://api.kanbert.com/api/v1/projects'Same logic using the DSL string:
curl -G \
--data-urlencode "filter=client.name contains 'Acme' and (shortcode = 'P-42' or shortcode startsWith 'P-')" \
'https://api.kanbert.com/api/v1/projects'Filter on sets and numeric comparisons:
curl -G \
--data-urlencode "filter=status in ['ACTIVE','PENDING'] and budget >= 1000" \
'https://api.kanbert.com/api/v1/projects'Null checks:
curl -G \
--data-urlencode "filter=primary_contact_id is null" \
'https://api.kanbert.com/api/v1/projects'Filtering works independently of sorting and pagination:
- Sorting: continue using the documented
sortparameter for each endpoint. - Pagination: use the default pagination options for the endpoint (cursor or page‑based) as documented.
- Includes: if the endpoint supports
include/fields(sparse fieldsets), you can combine them with filtering.
If the filter payload contains an unknown field, an unsupported operator for that field, or an invalid value type, the API returns a 400 Bad Request with details about the problem. Common cases:
- Unknown field name.
- Operator not allowed for the field type (e.g.,
containson a numeric field). - Malformed JSON or DSL expression.
Example error body:
{
"message": "Invalid filter",
"errors": [
{"field": "budget", "issue": "Operator 'contains' is not allowed for type 'number'"}
]
}- Prefer the JSON format for complex, programmatically built filters.
- Use the DSL for quick ad‑hoc queries and debugging.
- Use dot‑notation for related fields when the endpoint documents them (e.g.,
client.name). - For consistent dates, pass ISO‑8601 strings (e.g.,
2025-12-04T12:28:00Z).
Q: Can I mix JSON and DSL in one request?
A: No. Choose either JSON or DSL per request.
Q: Are and/or required?
A: In JSON array form, items are combined with AND by default. To mix AND/OR, use the object form with explicit groups, or the DSL with parentheses.
Q: Can I filter by nested relations?
A: Yes, when documented. Use dot‑notation like client.name.