Pagination, Filtering & Sorting
All list endpoints support pagination, filtering, sorting, and relation inclusion via query parameters.
Pagination
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
number | 1 |
Current page number (1-indexed) |
perPage |
number | 10 |
Number of items per page |
curl:
curl "https://api.incrm.app/api/v1/client?page=2&perPage=25" \
-H "X-Api-Key: incrm_your-key"
TypeScript SDK:
const { data } = await listClients({ query: { page: 2, perPage: 25 } })
Pagination Metadata
List responses include a meta object:
{
"success": true,
"data": [...],
"meta": {
"total": 150,
"lastPage": 6,
"currentPage": 2,
"perPage": 25,
"prev": 1,
"next": 3
}
}
| Field | Type | Description |
|---|---|---|
total |
number | Total number of matching records |
lastPage |
number | Last available page number |
currentPage |
number | Current page number |
perPage |
number | Items per page |
prev |
number | null | Previous page number, or null if on first page |
next |
number | null | Next page number, or null if on last page |
Traversing All Pages
To retrieve all records, iterate until meta.next is null:
import { InCRMClient, listClients } from '@incrm-app/sdk'
const incrm = new InCRMClient({
baseUrl: 'https://api.incrm.app',
apiKey: 'incrm_your-key',
})
let page = 1
const allClients = []
while (true) {
const { data: response } = await listClients({ query: { page, perPage: 100 } })
allClients.push(...response.data)
if (!response.meta.next) break
page = response.meta.next
}
console.log(`Fetched ${allClients.length} clients`)
Filtering (where)
The where parameter supports a powerful filter syntax for querying records.
Basic Equality
where=firstName:John
Operators
Use the operator syntax field:operator:value:
| Operator | Description | Example |
|---|---|---|
| (none) | Equals | where=status:ACTIVE |
gt |
Greater than | where=amount:gt:int(100) |
gte |
Greater than or equal | where=amount:gte:int(50) |
lt |
Less than | where=amount:lt:int(1000) |
lte |
Less than or equal | where=amount:lte:int(500) |
contains |
String contains | where=name:contains:john |
startsWith |
String starts with | where=name:startsWith:Jo |
endsWith |
String ends with | where=email:endsWith:.com |
Type Casting
Wrap values in type functions:
| Type | Syntax | Example |
|---|---|---|
| Integer | int(value) |
where=amount:gt:int(100) |
| Float | float(value) |
where=price:lt:float(99.99) |
| Boolean | bool(value) |
where=isActive:bool(true) |
| Date | date(value) |
where=createdAt:gt:date(2025-01-01) |
Multiple Conditions (AND)
Separate conditions with commas:
where=status:ACTIVE,firstName:contains:John
Conditions on the same field combine, which gives a range:
where=issueDate:gte:date(2025-01-01),issueDate:lte:date(2025-12-31T23:59:59.999Z)
OR Conditions
where=OR:[status:ACTIVE,status:PENDING]
NOT Conditions
where=NOT:status:ARCHIVED
JSON Filters
where also accepts a URL-encoded JSON object in Prisma's filter format. It can express what the string syntax cannot: nested AND/OR/NOT, fields of embedded objects (is), and lists of embedded objects (some, every, none).
where={"AND":[{"paymentStatus":{"in":["NotPaid","PartlyPaid"]}},{"clientInfo":{"is":{"name":{"contains":"acme","mode":"insensitive"}}}},{"lineItems":{"some":{"description":{"contains":"hosting"}}}}]}
Use Prisma operator names (equals, in, gte, contains, mode, ...). Raw MongoDB operators such as $where are not supported and return a 400 error.
Examples
curl — Active clients created after Jan 2025:
curl "https://api.incrm.app/api/v1/client?where=isActive:bool(true),createdAt:gt:date(2025-01-01)" \
-H "X-Api-Key: incrm_your-key"
curl — Invoices over $1000:
curl "https://api.incrm.app/api/v1/invoice?where=totalAmount:gt:int(1000)" \
-H "X-Api-Key: incrm_your-key"
Searching Files, Documents and Notes by Meaning
where matches fields. To find files, documents and notes by what they say, and your own earlier chats with Brane and subjects by what they were about, use GET /api/v1/workspace/search. It is a search by meaning, not a list endpoint: it takes q instead of where. Meaning is compared best within one language, so for documents in another language give the same phrase in that language too, separated by |: late delivery penalty | ugovorna kazna za kašnjenje finds a Croatian contract that says "ugovorna kazna".
| Parameter | Description |
|---|---|
q |
Required. What to look for, up to 500 characters; up to 3 phrasings of it separated by |. |
types |
Kinds of source, separated by commas: FILE, DOCUMENT, NOTE, CHAT (your chats with Brane), SUBJECT (your subjects). Default: all the caller may read. |
folderId |
Only files and documents in this folder of Files or below it (no notes, chats or subjects). |
limit |
Most sources to return: 10 by default, at most 25. |
Only sources the caller may open are returned, as GET /files/{id}, GET /document/{id}, GET /note/{id}, GET /ai-chat/{id} and GET /brane-subject/{id} decide it, and each kind needs its own read permission (files.read, documents.read, notes.read, aichats.read, braneSubjects.read). Chats and subjects are personal: only their own user finds them, never a colleague in the same business. Each result is one source, best first: type, id, name, folderPath, updatedAt, score (0 to 1) and up to 3 snippets with the page of a file; a chat also has archivedAt and purgedAt. Where search by meaning is not available or finds nothing, the words of q are looked for in names and text (match: TEXT, score: null). A file is searchable once its text is read; a document or note about 30 seconds after it was saved; a chat once Brane reviewed it (by its title, summary and open loops, never its messages), also as a trace after its messages were deleted (purgedAt set); a subject once it is made or its summary changes.
curl "https://api.incrm.app/api/v1/workspace/search?q=late%20delivery%20penalty%20%7C%20ugovorna%20kazna&types=FILE,DOCUMENT" \
-H "X-Api-Key: incrm_your-key"
Sorting (orderBy)
Sort results using field:direction pairs, separated by commas:
orderBy=lastName:asc,firstName:asc
| Direction | Description |
|---|---|
asc |
Ascending |
desc |
Descending |
curl:
curl "https://api.incrm.app/api/v1/invoice?orderBy=createdAt:desc&perPage=50" \
-H "X-Api-Key: incrm_your-key"
TypeScript SDK:
const { data } = await listInvoices({
query: { orderBy: 'createdAt:desc', perPage: 50 },
})
Error on Invalid Sort
{
"success": false,
"error": {
"code": 400011,
"message": "Invalid sorting order"
}
}
Relation Inclusion (include)
Expand related entities using the include parameter. Provide a comma-separated list of relation names:
include=invoices,contacts
Prefix with - to exclude a default relation:
include=-contacts
curl:
curl "https://api.incrm.app/api/v1/client/6507a1b2c3d4e5f6a7b8c9d0?include=invoices,contacts" \
-H "X-Api-Key: incrm_your-key"
Response (with included relations):
{
"success": true,
"data": {
"id": "6507a1b2c3d4e5f6a7b8c9d0",
"firstName": "John",
"lastName": "Doe",
"invoices": [
{ "id": "...", "totalAmount": 500, "status": "PAID" }
],
"contacts": [
{ "id": "...", "type": "EMAIL", "value": "john@example.com" }
]
}
}
Available relations depend on the entity. Refer to the OpenAPI spec at GET /api/v1/openapi.json for the complete list of relations per resource.
Error on Invalid Include
{
"success": false,
"error": {
"code": 400019,
"message": "Invalid query format"
}
}