Searching & filtering
Three mechanisms, stackable. All are query-string parameters on list endpoints.
1. Text search
| Param | Type | Notes |
|---|---|---|
searchBy | string | Comma-separated field names to search across. |
searchValue | string | The term. Matched as a case-insensitive regex. |
?searchBy=name,email&searchValue=ada
Omitting searchBy falls back to the endpoint's default search fields. searchValue is trimmed; an empty value is ignored rather than matching everything.
2. Simple filters
filters takes a JSON object, URL-encoded. Keys are field paths, values are what to match.
?filters={"stage":"Qualified","status":"Hot"}
const qs = new URLSearchParams({
p: "1",
n: "50",
filters: JSON.stringify({ stage: "Qualified", status: "Hot" }),
});
await leadx(`/lead?${qs}`);
Two conversions happen automatically:
- A value that is a valid 24-character ObjectId string is cast to an ObjectId — so
{"team":"665f..."}matches the reference, not the string. - An array value becomes an
$in.{"stage":["New","Contacted"]}matches either. Array members are individually ObjectId-cast too.
Malformed JSON is silently treated as {} — no error, just an unfiltered result. Validate before you send.
3. Advanced filters
advancedFilters takes a JSON condition tree for anything simple filters can't express — operators, groups, and OR/AND nesting. It is the same structure the web app's filter builder emits, and the same one segments are stored as.
{
"combinator": "and",
"conditions": [
{ "fieldId": "stage", "operator": "in", "value": ["Qualified", "Negotiation"] },
{ "fieldId": "createdAt", "operator": "gte", "value": "2026-01-01" },
{
"combinator": "or",
"conditions": [
{ "fieldId": "status", "operator": "equals", "value": "Hot" },
{ "fieldId": "priority","operator": "equals", "value": "High" }
]
}
]
}
Conditions targeting a lead's product/service or contact fields are recognised by prefix (productService., productServices., contact.) and routed to the right collection automatically.
Like filters, unparseable JSON is ignored rather than rejected.
Restricting to specific records
| Param | Type | Notes |
|---|---|---|
ids | string[] | Only these documents. |
nids | string[] | Everything except these. |
Repeat the key for arrays: ?ids=665f...&ids=6660.... A single value is accepted and wrapped.
Combining
All of the above intersect (AND) with each other and with the mandatory company scope:
?p=1&n=50
&searchBy=name,email&searchValue=acme
&filters={"stage":"Qualified"}
&sortBy=createdAt&sortOrder=desc
Counting without fetching
Ask for the smallest possible page and read totalCount:
?p=1&n=1&filters={"stage":"Won"}