Rows

Read a page of rows from one table, optionally sorted, searched, and filtered. The response bundles the column metadata together with the page so a grid can render without a second request.

Request

GET /api/tables/{table}/rows

Path parameters

NameTypeNotes
tablestringReal table name from GET /api/tables.

Query parameters

NameTypeDefaultNotes
page integer ≥ 1 1 1-indexed page number. Values below 1 are clamped to 1.
page_size integer 50 Rows per page. Clamped to the range [1, 1000].
sort_column string A real column name from GET /api/tables/{table}/columns. Validated against the live schema; unknown or unsafe names return 400.
sort_direction asc or desc asc Only desc / DESC selects descending order; anything else (including omitted) sorts ascending. Has no effect unless sort_column is also set.
search string Case-insensitive substring match (ILIKE '%value%') applied across every text-like column — text, character varying, character, and uuid. Non-text columns are not included in the search.
filter.<column> string (repeatable) Per-column filter. Any query parameter whose name begins with filter. is treated as a filter on the column named after the dot. Multiple filters are AND-ed. See "Filter semantics" below.
Filter semantics

For most columns the filter runs as "column"::text ILIKE '%value%' — a case-insensitive substring match after casting to text. For boolean columns the filter is an exact match: values yes, true, t, 1 match TRUE; no, false, f, 0 match FALSE; anything else matches no rows.

Response

200 OK. A JSON object describing the requested page.

FieldTypeNotes
columnsarrayThe same shape as GET /api/tables/{table}/columns. Included so the client can render headers and NULL cells without a second round-trip.
rowsarray of objectsOne object per row, keyed by real column name. Values are JSON-typed according to the source SQL type — see "Value encoding" below.
total_rowsintegerTotal number of rows matching the search and filters across the whole table, not just the returned page. Use this for pagination controls.
pageintegerThe page that was returned (after clamping).
page_sizeintegerThe page size that was used (after clamping).

Value encoding

SQL typeJSON representation
smallint, integerJSON number.
bigintJSON number when the absolute value fits in 253, otherwise a JSON string to preserve precision in JavaScript clients.
real, double precisionJSON number.
numericJSON string — arbitrary-precision decimals are never widened to a float.
booleanJSON boolean.
json, jsonbThe parsed JSON value, inlined.
timestamp without time zoneString, formatted "YYYY-MM-DD HH:MM:SS".
timestamp with time zoneRFC 3339 string (UTC).
dateString, formatted "YYYY-MM-DD".
time with/without time zoneString, formatted "HH:MM:SS".
uuidString.
OtherString — the value as PostgreSQL would render it via ::text.
SQL NULLJSON null.

Example

curl "http://127.0.0.1:3141/api/tables/vehicles_log/rows\
?page=1\
&page_size=2\
&sort_column=recorded_at\
&sort_direction=desc\
&search=ADT\
&filter.vehicle_id=ADT3\
&filter.is_active=yes"
{
  "columns": [
    { "name": "id", "display_name": "Id", "data_type": "bigint",
      "display_type": "Number", "is_nullable": false, "is_primary_key": true },
    { "name": "vehicle_id", "display_name": "Vehicle", "data_type": "character varying",
      "display_type": "Text", "is_nullable": false, "is_primary_key": false },
    { "name": "posn_lat", "display_name": "Latitude", "data_type": "double precision",
      "display_type": "Decimal", "is_nullable": true, "is_primary_key": false },
    { "name": "is_active", "display_name": "Active", "data_type": "boolean",
      "display_type": "Yes/No", "is_nullable": false, "is_primary_key": false },
    { "name": "recorded_at", "display_name": "Recorded At",
      "data_type": "timestamp with time zone", "display_type": "Date & Time",
      "is_nullable": false, "is_primary_key": false }
  ],
  "rows": [
    {
      "id": 523401,
      "vehicle_id": "ADT3",
      "posn_lat": 52.41933,
      "is_active": true,
      "recorded_at": "2026-04-12T17:42:05+00:00"
    },
    {
      "id": 523397,
      "vehicle_id": "ADT3",
      "posn_lat": null,
      "is_active": true,
      "recorded_at": "2026-04-12T17:41:55+00:00"
    }
  ],
  "total_rows": 18422,
  "page": 1,
  "page_size": 2
}

Errors

StatusWhen
400sort_column or a filter.<name> references an unknown column, or the name contains characters other than letters, digits, underscore, hyphen, or space. Body: {"error": "Unknown sort column: X"} or {"error": "Invalid filter column name: X"}.
404The table is not in the allow-list or does not exist.
503The server is still in setup mode.
500The query failed. See the server log for detail.

Related