Filtering rows
Search rows by text and filter them by column values.
Text search
Both row endpoints search cell values, ignoring case:
curl "https://api-v2.baseloop.io/v1/tables/<tableId>/rows?q=acme" \
-H "Authorization: Bearer <api-key>"An empty q is ignored. In POST /rows/query the search goes in query (or q). When both are sent, query wins, even when it is empty.
Filters
Filters need POST /tables/{tableId}/rows/query. Each rule compares one column with a value:
curl -X POST https://api-v2.baseloop.io/v1/tables/<tableId>/rows/query \
-H "Authorization: Bearer <api-key>" \
-H "Content-Type: application/json" \
-d '{
"limit": 100,
"query": "acme",
"filters": {
"combinator": "and",
"rules": [
{ "fieldId": "<fieldId>", "operator": "contains", "value": "Acme" }
]
}
}'fieldIdis a column ID fromGET /tables/{tableId}/schema. An unknown ID returns400.combinatoris"and"(the default, every rule must match) or"or"(any rule).valueis left out fornull,notNulland the run-status operators.
Operators by column type
Each column type accepts its own operators. An operator the column does not accept returns 400, and the message lists the ones it does.
| Column type | Operators |
|---|---|
text | = != contains doesNotContain startsWith containsAnyOf doesNotContainAnyOf in notIn |
url, image, formula | = != contains doesNotContain startsWith containsAnyOf doesNotContainAnyOf |
email, phone_number | = != contains doesNotContain startsWith |
number | = != > >= < <= |
date | = < > isDatePreset between |
boolean, member | = != |
select | = != in notIn |
multi_select | in notIn |
action, webhook | = != contains doesNotContain startsWith hasError hasNoError hasNotRun runConditionNotMet isFound isNotFound |
null and notNull work on every column. hasError, hasNoError, hasNotRun and runConditionNotMet also work on any column that runs an action or AI, whatever its type.
Values
| Operator | Value |
|---|---|
containsAnyOf, doesNotContainAnyOf | A list of up to 20 strings: ["acme", "globex"]. Values past 20 are ignored. |
in, notIn | A list: ["customer", "prospect"] |
isDatePreset | One of today, tomorrow, yesterday, thisWeek, lastWeek, thisMonth, lastMonth, thisQuarter, lastQuarter, thisYear, lastYear, last7Days, last14Days, last30Days, last60Days, last90Days, last180Days, last365Days |
between | { "start": "2026-01-01T00:00:00Z", "end": "2026-03-31T23:59:59Z" } |
| Everything else | Text, a number or true/false |
Values that are not text are sent on as JSON text, and each value can be up to 1,000 characters.
Groups
A rule can also be a group with its own combinator and rules. This reads as company contains "Acme" AND (status = "customer" OR status = "prospect"):
{
"filters": {
"combinator": "and",
"rules": [
{ "fieldId": "<companyFieldId>", "operator": "contains", "value": "Acme" },
{
"combinator": "or",
"rules": [
{ "fieldId": "<statusFieldId>", "operator": "=", "value": "customer" },
{ "fieldId": "<statusFieldId>", "operator": "=", "value": "prospect" }
]
}
]
}
}Filters allow 5 levels, counting the top level, so groups nest 4 deep. Each group holds up to 25 entries, and all groups together hold up to 100, where a nested group counts as one entry in its parent.