query_table_rows
Read rows from a table, with the row_id needed to edit or delete them.
Rows come back in table order (top row first), which for a log-style table is the
oldest row — pass sort to read the newest first.
Parameters#
| Name | Type | Required | Default |
|---|---|---|---|
table_id | string | yes | |
limit | integer | no | 50 |
offset | integer | no | 0 |
filters | JSON | no | null |
sort | JSON | no | null |
search | string | no | null |
total in the response is every matching row, not the page size — page through
the rest with offset.
Filtering#
filters is a JSON array of conditions, ANDed together:
[{"column": "month", "operator": "is", "value": "2026-08-01"}]Each condition is {"column": "<key or id>", "operator": "<op>", "value": <v>}.
Column keys come from get_table; ids work too.
Operators#
Which operators a column accepts depends on its type, and get_table reports the
exact list per column as valid_operators — read it rather than guessing.
| Group | Operators |
|---|---|
| Any type | is_empty, is_not_empty |
| Text / email / url | contains, not_contains, starts_with, ends_with |
| Number | gt, gte, lt, lte, between |
| Date / datetime | before, after, on, between |
| Select / multi-select | in, not_in, has_all |
between takes a two-element list: {"operator": "between", "value": [100, 200]}.
OR and nested groups#
For anything other than a plain AND, pass a group instead of an array:
{
"conjunction": "or",
"conditions": [
{"column": "status", "operator": "is", "value": "churned"},
{"column": "mrr", "operator": "lt", "value": 100}
]
}Groups nest, so “active AND (gold OR spend over 1000)” is expressible:
{
"conjunction": "and",
"conditions": [
{"column": "status", "operator": "is", "value": "active"},
{"conjunction": "or", "conditions": [
{"column": "tier", "operator": "is", "value": "gold"},
{"column": "spend", "operator": "gt", "value": 1000}
]}
]
}A bare array is exactly {"conjunction": "and", "conditions": [...]}.
Searching#
search matches free text against every text, email and url column at once.
Use it when you do not know which column holds the value; use filters when you
do. It ANDs with filters — it never widens them.
{"table_id": "dtbl_abc123", "search": "acme"}Searching a table with no text column returns a search_note saying so, because
zero rows would otherwise read as proof the record does not exist.
Sorting#
[{"column": "created", "direction": "desc"}]Multiple keys are applied in order.
Errors#
This tool fails closed. An unknown column, an operator the column’s type does not support, an unusable value, or a sort key that cannot be honored all come back as an error — never as an unfiltered read that looks like a real answer. The error names what was wrong and, for an operator mismatch, lists the operators that column does accept.
Returns#
{table_id, total, offset, rows: [{row_id, values: {column_key: value}}]}Extend this page freely — the generator never overwrites an existing file.
Media references#
Media cells return ordered arrays of workspace file IDs. When a page references media, media_files contains the corresponding id, current path, file_asset_id, version, mimetype, and a fresh preview url. Missing or archived files return only their ID and missing: true. Use read_file with the path and view_media to inspect the asset; use the durable asset ID when preparing an ad. Do not persist the temporary preview URL. Media filters support is_empty and is_not_empty.