Base & Tables API
Manage bases, tables, fields, and records. This router provides full CRUD operations for your database infrastructure.
Endpoints
/api/v1/tables/createDatabaseCreate a new database (base). Returns the created database with its ID.
Parameters
name | stringrequired | Name for the new database/base |
description | string | Optional description of the database |
icon | string | Icon name (e.g., "database", "folder") |
color | string | Hex color code (e.g., "#3B82F6") |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/createDatabase \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "example",
"description": "example",
"icon": "example"
}'/api/v1/tables/listDatabasesList all databases (bases) for the current user. Returns array with id, name, description, tables[]. Use this first to get database IDs.
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/listDatabases \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{}'/api/v1/tables/getDatabaseByIdGet a specific database with its tables
Parameters
id | stringrequired | Database ID from listDatabases |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getDatabaseById \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/updateDatabaseUpdate database properties. Only provided fields are updated.
Parameters
id | stringrequired | Database ID from listDatabases |
name | string | New name for the database |
description | string | New description |
icon | string | New icon name |
color | string | New hex color code |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateDatabase \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"name": "example",
"description": "example"
}'/api/v1/tables/deleteDatabasePermanently delete a database and all its contents
Parameters
id | stringrequired | Database ID to delete. WARNING: This permanently deletes all tables and data. |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/deleteDatabase \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/createTableCreate a new table in a database. Returns the created table.
Parameters
databaseId | stringrequired | Database ID from listDatabases where the table will be created |
name | stringrequired | Name for the new table |
description | string | Optional description of the table |
icon | string | Icon name (e.g., "table", "users") |
color | string | Hex color code (e.g., "#10B981") |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/createTable \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"databaseId": "example",
"name": "example",
"description": "example"
}'/api/v1/tables/listTablesList all tables across all databases. Returns array with id, name, databaseId. Use getTableById for full details.
Parameters
databaseId | string | Limit to one base — omit for all tables across all bases |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/listTables \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"databaseId": "example"
}'/api/v1/tables/getViewsByTableIdGet all views for a table
Parameters
tableId | stringrequired | Table ID from listTables |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getViewsByTableId \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example"
}'/api/v1/tables/getFieldsByTableIdGet all fields/columns for a table. Returns field IDs needed for createRow data keys.
Parameters
tableId | stringrequired | Table ID from listTables |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getFieldsByTableId \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example"
}'/api/v1/tables/getTableByIdGet table with fields and views. Returns field IDs needed for row data.
Parameters
id | stringrequired | Table ID from listTables |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getTableById \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/updateTableUpdate table properties. Only provided fields are updated.
Parameters
id | stringrequired | Table ID from listTables |
name | string | New name for the table |
description | string | New description |
icon | string | New icon name |
color | string | New hex color code |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateTable \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"name": "example",
"description": "example"
}'/api/v1/tables/deleteTablePermanently delete a table and all its data
Parameters
id | stringrequired | Table ID to delete. WARNING: This permanently deletes all rows and fields. |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/deleteTable \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/createFieldCreate a new field/column in a table
Parameters
tableId | stringrequired | Table ID from listTables |
name | stringrequired | Name for the new field/column |
fieldType | stringrequired | Field type: "text", "number", "select", "multiselect", "date", "datetime", "checkbox", "url", "email", "phone", "file", "formula", "rating", "currency", "percent", "duration", "status", "button", "link", "lookup", "rollup". READ-ONLY computed types (writes to them are dropped): "hash" = Hash ID, a read-only stable per-row identifier — it does NOT hash a value you supply (to store a hashed value, compute it yourself and use text/secret); "created_time"/"updated_time" = system timestamps; "formula"/"lookup"/"rollup" = computed. Numbers are exact only up to 2^53 — unsafe integers are rejected with guidance; store long IDs, account numbers, and IMEIs as text. |
description | string | Optional description of the field |
required | boolean | Must be false or omitted. Required fields are not supported - UI creates blank rows first. |
unique | boolean | Whether values must be unique (default: false) |
defaultValue | any | Default value for new rows |
options | array | For select/multiselect: [{value: "opt1", label: "Option 1", color: "#3b82f6"}] |
statusLabels | array | For status: [{value: "todo", label: "To Do", color: "#6b7280"}] |
formulaConfig | object | For formula: {formula: "{Field A} * {Field B}", resultType: text|number|date|checkbox}. Non-volatile formula values are materialized (stored on the row, auto-recalculated when inputs change — including via links) and are filterable/queryable everywhere; formulas using NOW()/TODAY() are volatile: display-only, empty when filtering or sorting, not filterable |
buttonConfig | object | For button: {actionType: "flow", flowId: "xxx"} |
numberFormatConfig | object | For number: {decimalPlaces: 2, useThousandSeparator: true} |
currencyFormatConfig | object | For currency: {currencySymbol: "$", symbolPosition: "before"} |
percentFormatConfig | object | For percent: {decimalPlaces: 1} |
lookupConfig | object | For lookup: {relationshipFieldId: "<link field id>", sourceFieldId: "<field id on linked table>", aggregation?: CONCATENATE|FIRST|LAST|ARRAY|COUNT|SUM|AVG|MIN|MAX (default CONCATENATE; COUNT counts NON-EMPTY VALUES — use a rollup COUNT to count linked records), filter?: {logic, conditions:[{fieldId,operator,value}]} over LINKED-table fields — only matching linked rows are aggregated}. Computed by Postgres; scalar (non-chained) aggregations are filterable everywhere — view filters, filterRows, and published-app entities.filter() |
rollupConfig | object | For rollup: {relationshipFieldId: "<link field id>", sourceFieldId: "<field id on linked table>", aggregation: COUNT|COUNT_EMPTY|COUNT_FILLED|COUNT_UNIQUE|SUM|AVG|MIN|MAX|MEDIAN|CONCATENATE|ARRAY|ARRAY_UNIQUE|ARRAY_COMPACT (default COUNT; COUNT counts LINKED RECORDS incl. empty values — COUNT_FILLED matches lookup COUNT), filter?: {logic, conditions:[{fieldId,operator,value}]} over LINKED-table fields — only matching linked rows are aggregated}. Computed by Postgres; scalar (non-chained) aggregations are filterable everywhere — view filters, filterRows, and published-app entities.filter() |
linkedTableId | string | For link field: target table ID |
linkType | string | Link relationship type |
displayOrder | string | Fractional order string (e.g., "a0", "b0") |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/createField \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"name": "example",
"fieldType": "example"
}'/api/v1/tables/updateFieldUpdate field properties. Only provided fields are updated.
Parameters
id | stringrequired | Field ID from getFieldsByTableId |
name | string | New name for the field |
fieldType | string | Field type |
description | string | New description |
required | boolean | Must be false or omitted. Required fields are not supported - UI creates blank rows first. |
unique | boolean | Whether values must be unique |
defaultValue | any | Default value for new rows |
options | array | For select/multiselect: [{value: "opt1", label: "Option 1", color: "#3b82f6"}] |
statusLabels | array | For status: [{value: "todo", label: "To Do", color: "#6b7280"}] |
formulaConfig | object | For formula: {formula: "{Field A} * {Field B}", resultType: text|number|date|checkbox}. Non-volatile formula values are materialized (stored on the row, auto-recalculated when inputs change — including via links) and are filterable/queryable everywhere; formulas using NOW()/TODAY() are volatile: display-only, empty when filtering or sorting, not filterable |
linkedTableId | string | For link field: target table ID |
linkType | string | Link relationship type |
linkDisplayMode | string | How to display linked records |
linkDisplayFieldId | string | Which field to show from linked records |
allowMultipleLinks | boolean | Whether multiple links are allowed |
linkOnDelete | string | For link fields: what happens to linking rows when a linked record is deleted. RESTRICT blocks the delete; CASCADE deletes the linking rows too (chains, capped at 500 rows per delete); SET_NULL (default) just removes the connection. |
buttonConfig | object | For button: {actionType: "flow", flowId: "xxx"} |
numberFormatConfig | object | For number: {decimalPlaces: 2, useThousandSeparator: true} |
currencyFormatConfig | object | For currency: {currencySymbol: "$", symbolPosition: "before"} |
percentFormatConfig | object | For percent: {decimalPlaces: 1} |
lookupConfig | object | For lookup: {relationshipFieldId: "<link field id>", sourceFieldId: "<field id on linked table>", aggregation?: CONCATENATE|FIRST|LAST|ARRAY|COUNT|SUM|AVG|MIN|MAX (default CONCATENATE; COUNT counts NON-EMPTY VALUES — use a rollup COUNT to count linked records), filter?: {logic, conditions:[{fieldId,operator,value}]} over LINKED-table fields — only matching linked rows are aggregated}. Computed by Postgres; scalar (non-chained) aggregations are filterable everywhere — view filters, filterRows, and published-app entities.filter() |
rollupConfig | object | For rollup: {relationshipFieldId: "<link field id>", sourceFieldId: "<field id on linked table>", aggregation: COUNT|COUNT_EMPTY|COUNT_FILLED|COUNT_UNIQUE|SUM|AVG|MIN|MAX|MEDIAN|CONCATENATE|ARRAY|ARRAY_UNIQUE|ARRAY_COMPACT (default COUNT; COUNT counts LINKED RECORDS incl. empty values — COUNT_FILLED matches lookup COUNT), filter?: {logic, conditions:[{fieldId,operator,value}]} over LINKED-table fields — only matching linked rows are aggregated}. Computed by Postgres; scalar (non-chained) aggregations are filterable everywhere — view filters, filterRows, and published-app entities.filter() |
displayOrder | number | Display order position |
isVisible | boolean | Whether field is visible |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateField \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"name": "example",
"fieldType": "example"
}'/api/v1/tables/deleteFieldPermanently delete a field/column and all its data
Parameters
id | stringrequired | Field ID to delete. WARNING: This permanently deletes all data in this column. |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/deleteField \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/createRowCreate a new row in a table. Data keys must be field IDs, not field names.
Parameters
tableId | stringrequired | Table ID from listTables |
data | objectrequired | Object where keys are FIELD IDs from getFieldsByTableId, values are cell values. Example: {"fieldId1": "text", "fieldId2": 123} |
rowOrder | string | Fractional order string for positioning. Leave empty to append at end. |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/createRow \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"data": {},
"rowOrder": "example"
}'/api/v1/tables/reportAnswer a numbers question about a table: counts, totals, averages per slice
Parameters
filter | any | Which rows count: {logic: "and"|"or", conditions: [{fieldId, operator, value}]} — the view filter language |
groupBy | array | Up to 3 slices |
measures | arrayrequired | 1 to 8 numbers to work out per slice |
having | array | Keep only slices whose measure passes (up to 4) |
sort | array | Order by group or measure names (up to 3) |
limit | integer | Slices per answer, 1-1000 (default 100) |
offset | integer | Slices to skip, for the next page (max 100000) |
percentOfTotal | string | The `as` of a count or sum measure: adds each slice's share of the whole (0-1) |
timeZone | string | IANA time zone for date slices, e.g. "Europe/Berlin" (default UTC) |
tableId | stringrequired | Table ID from listTables |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/report \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"filter": {},
"groupBy": {},
"measures": {}
}'/api/v1/tables/getRowCountGet total row count for a table. Lightweight operation.
Parameters
tableId | stringrequired | Table ID from listTables |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getRowCount \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example"
}'/api/v1/tables/getRowsGet rows from a table with pagination. Returns row data with field IDs as keys.
Parameters
tableId | stringrequired | Table ID from listTables |
limit | number | Rows to return, 1-1000 (default: 100). Values outside the range are REJECTED, not clamped — page with offset for more |
offset | number | Number of rows to skip for pagination |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getRows \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"limit": 0,
"offset": 0
}'/api/v1/tables/updateRowUpdate an existing row. Merges provided data with existing data.
Parameters
id | stringrequired | Row ID from getRows |
data | objectrequired | Object with field IDs as keys and new values. Only provided fields are updated. |
metadata | object | Optional metadata to merge with existing |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateRow \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"data": {},
"metadata": {}
}'/api/v1/tables/restoreRowUndo a row delete: bring back a row this same person deleted (with deleteRow or bulkDeleteRows) in the last ten minutes, at its old id, exactly as it was (its values are the copy kept when it was deleted). Params: tableId, rowId (the deleted row's id), rowOrder? (a row position the grid made, e.g. one taken from getRows; anything else is refused; default: where it was). Each delete can be undone once. A row deleted by someone else, longer ago, or never deleted answers "Row not found". Returns { id, tableId, data, rowOrder, createdAt, updatedAt } (secret values masked).
Parameters
tableId | stringrequired | The table the row was deleted from |
rowId | stringrequired | The deleted row's id |
rowOrder | string | Where to put it back (a row position the grid made; a bad one is refused); default: where it was |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/restoreRow \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"rowId": "example",
"rowOrder": "example"
}'/api/v1/tables/deleteRowPermanently delete a single row
Parameters
id | stringrequired | Row ID to delete |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/deleteRow \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/bulkDeleteRowsDelete multiple rows. Params: tableId, rowIds (array of row IDs).
Parameters
tableId | stringrequired | |
rowIds | arrayrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/bulkDeleteRows \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"rowIds": {}
}'/api/v1/tables/createViewCreate a new view. Params: tableId (required), name (required), viewType (required: "grid", "kanban", "calendar", "gallery", "form"), description, filterConfig, sortConfig, groupConfig, visibleFields (array of field IDs).
Parameters
tableId | stringrequired | |
name | stringrequired | |
viewType | stringrequired | |
description | string | |
filterConfig | any | |
sortConfig | any | |
groupConfig | any | |
visibleFields | array | |
columnWidths | any | |
isDefault | boolean |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/createView \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"name": "example",
"viewType": "example"
}'/api/v1/tables/updateViewUpdate view settings. Params: id (view ID), name, filterConfig, sortConfig, groupConfig, visibleFields, etc.
Parameters
id | stringrequired | |
name | string | |
description | string | |
filterConfig | any | |
sortConfig | any | |
groupConfig | any | |
visibleFields | array | |
columnWidths | any | |
isDefault | boolean | |
metadata | any |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateView \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"name": "example",
"description": "example"
}'/api/v1/tables/getViewsList all views for a table. Param "tableId". Returns array with id, name, viewType, filterConfig, sortConfig.
Parameters
tableId | stringrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getViews \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example"
}'/api/v1/tables/reorderViewChange view position. Params: viewId, newOrderIndex (string).
Parameters
viewId | stringrequired | |
newOrderIndex | stringrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/reorderView \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"viewId": "example",
"newOrderIndex": "example"
}'/api/v1/tables/duplicateViewCopy a view. Params: id (view ID to copy), name (optional, for the copy).
Parameters
id | stringrequired | |
name | string |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/duplicateView \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"name": "example"
}'/api/v1/tables/setDefaultViewSet which view opens by default. Params: id (view ID), tableId.
Parameters
id | stringrequired | |
tableId | stringrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/setDefaultView \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example",
"tableId": "example"
}'/api/v1/tables/deleteViewDelete a view. Param "id" is the view ID.
Parameters
id | stringrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/deleteView \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "example"
}'/api/v1/tables/updateFieldOrderChange field position. Params: fieldId, newOrder (fractional string).
Parameters
fieldId | stringrequired | |
newOrder | stringrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateFieldOrder \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"fieldId": "example",
"newOrder": "example"
}'/api/v1/tables/updateTableOrderChange table position in database. Params: tableId, newOrder (string like "a0", "b0" for fractional ordering).
Parameters
tableId | stringrequired | |
newOrder | stringrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateTableOrder \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"newOrder": "example"
}'/api/v1/tables/updateFieldWidthSet column width in pixels. Params: fieldId, width (number, e.g., 200).
Parameters
fieldId | stringrequired | |
width | numberrequired |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateFieldWidth \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"fieldId": "example",
"width": 0
}'/api/v1/tables/updateRowOrderUpdate row display order for row drag-and-drop
Parameters
rowId | stringrequired | Row ID to reorder |
newOrder | stringrequired | New fractional order string |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/updateRowOrder \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"rowId": "example",
"newOrder": "example"
}'/api/v1/tables/bulkUpdateRowsUpdate multiple rows at once. Each update merges its data with the existing row data — like updateRow but batched.
Parameters
tableId | stringrequired | Table ID from listTables |
updates | arrayrequired | Array of row updates |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/bulkUpdateRows \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"updates": {}
}'/api/v1/tables/exportTableExport all table data for download
Parameters
tableId | stringrequired | Table ID to export |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/exportTable \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example"
}'/api/v1/tables/importRowsBulk import rows. Use matchFieldsByName=true (default) to use field names as keys. Send about 5,000 rows a call, fewer for a wide table: a call takes at most 100,000 items in one list and 1,000,000 values in all. A file in several calls: call it with checkOnly=true and firstRowNumber for every part first (nothing is written), then import the parts, so a wrong row anywhere imports nothing, except values that clash between parts or a limit reached by the parts together.
Parameters
tableId | stringrequired | Table ID from listTables |
rows | arrayrequired | Array of row data. When matchFieldsByName=true, use field NAMES as keys. When false, use field IDs. LINKED-RECORD columns resolve per value: sibling "<Field> (id)" column → row IDs → JSON-array string (comma-safe) → exact label → unique case-insensitive label; unresolvable values are returned in unresolvedLinks (row still imports, link skipped — never guessed, never auto-created). Relations are written both directions. |
matchFieldsByName | boolean | If true, match columns by field name. If false, use field IDs as keys (default: true) |
fieldDefinitions | array | Optional field definitions to create new fields during import |
checkOnly | boolean | Check these rows exactly as an import would, writing nothing (no rows, no columns). To import a file in several calls, check every part first, then import them: a wrong row anywhere then imports nothing, except values that clash between parts or a limit reached by the parts together. |
firstRowNumber | integer | The file's row number of rows[0] when a file goes in several calls (default 1), so an error names the row in the file. |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/importRows \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"rows": {},
"matchFieldsByName": true
}'/api/v1/tables/exportBaseExport one whole base (all its tables, fields, rows and views) as one file in the format tables_importBase takes. Param "databaseId" (from listDatabases). Returns { formatVersion, exportedAt, base, tables: [{ name, fields, rows, views }] }, the same file the Export button saves. Each row carries its id (__rowId) so an import can put linked records back; a secret column comes back blank. The file is at most 256 KB: a bigger base is refused with its size, so read it one table at a time with tables_getRows instead. For one table only use tables_exportTable.
Parameters
databaseId | stringrequired | The base to export (an id from listDatabases) |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/exportBase \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"databaseId": "example"
}'/api/v1/tables/importBaseMake a new base from a file tables_exportBase gave. Params: data (required: the whole file, exactly as exported), name (optional: the new base's name; default the file's own name). It always makes a new base with all-new ids in this workspace and never changes, overwrites or deletes an existing base, table or row; a base of the same name becomes a second base. It counts against the plan: the number of bases, the rows a table may hold on plans with a row limit, and the database storage; when a limit is reached nothing is made and the answer says which. Returns { databaseId, tablesCreated, linkedRecordsRestored, unresolvedLinks, message }; unresolvedLinks lists link cells that named a row the file does not hold (nothing is linked for them).
Parameters
name | string | Name for the new base (default: the file's own name) |
data | objectrequired | The whole file tables_exportBase gave, exactly as exported |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/importBase \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "example",
"data": {}
}'/api/v1/tables/filterRowsFilter rows by field values using postgres-side WHERE clauses (uses GIN index on data, scales to large tables). Returns { rows, total, tableId, tableName, limit, offset }. Same operator dict as the published-app runtime SDK's entities.<Table>.filter(). Unknown field keys and unknown operators throw 400 with the valid options. Scalar lookup/rollup fields ARE filterable (computed in SQL — direct sources only; chained/list aggregations throw 400 explaining why). Formula fields ARE filterable too (values are materialized into stored data on every write) — EXCEPT formulas using NOW()/TODAY(), which have no stored value and throw 400 with guidance.
Parameters
tableId | stringrequired | Table ID to filter |
filter | object | Filter object. Keys are field IDs OR field names (case-insensitive). Multiple keys are AND-ed; { "$or": [ {...}, {...} ] } and { "$and": [...] } group full filter objects and nest arbitrarily. Each value is either a plain primitive (equality), or an operator dict. Operators: $eq, $ne, $gt, $gte, $lt, $lte, $between ([min,max] inclusive), $contains, $startsWith, $endsWith, $regex (Postgres syntax, case-sensitive — prefix (?i) for insensitive), $in, $nin (blanks count as not-in-list), $not (complement of an inner operator dict), $isEmpty, $isNotEmpty. Field-to-field: $eqField/$neField/$gtField/$gteField/$ltField/$lteField compare against ANOTHER field of the same row by name/id — { "Spent": { "$gtField": "Budget" } } finds over-budget rows. Example: { "Status": "todo", "Priority": { "$between": [5, 9] }, "$or": [{ "Tags": { "$contains": "urgent" } }, { "Due": { "$isEmpty": true } }] } Validation: unknown field keys, unknown operators, and operator/value type mismatches throw 400 with the valid options — typos surface immediately instead of returning all (or wrong) rows. Semantics: $contains is case-insensitive and matches LITERALLY (%, _ and \ are escaped); $eq is exact and case-sensitive with NO type coercion ({Score: "50"} does not match the number 50); { field: null } means "is empty"; $in: [] matches NOTHING. Field types: multiselect filters by MEMBERSHIP ($contains value, $in = any-of, plain scalar = has that tag). created_time/updated_time compare as dates ($gte/$lt ranges; ISO strings). Link fields filter by linked ROW ID via the relation table ($contains id, $in [ids], $isEmpty/$isNotEmpty). Caveat: $gt/$gte/$lt/$lte on text fields that store numeric-looking strings ("16", "8") use LEXICOGRAPHIC comparison, so "8" > "10" is true. Use these operators only on fields whose values are stored as proper numbers, or filter then sort/compare client-side for text-stored numerics. |
sort | string | Sort spec — rowOrder, createdAt, updatedAt, or ANY FIELD NAME/ID, optionally prefixed with "-" for descending (e.g. "-Total"). Defaults to rowOrder asc. Numbers sort numerically, text case-insensitively, blanks always last; scalar lookup/rollup and self-contained formulas sort server-side too. Link fields, volatile formulas and list aggregations are not sortable (clear 400). Unknown keys throw 400 — never silently ignored. |
limit | number | Max rows per page (default: 100, max: 1000) |
offset | number | Skip results for pagination |
includeReadable | boolean | Include human-readable field-name keys in output (extra cost — set true only when you need it; default false) |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/filterRows \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"filter": {},
"sort": "example"
}'/api/v1/tables/searchRowsSubstring search across all field values in a table. Postgres-side via data::text. No 500-row cap.
Parameters
tableId | stringrequired | Table ID to search in |
query | stringrequired | Search query string. Matches anywhere in the row's serialized data (field IDs and values). |
limit | number | Max results per page (default: 50, max: 500) |
offset | number | Skip results for pagination |
includeReadable | boolean | Include human-readable field names in output |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/searchRows \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"query": "example",
"limit": 0
}'/api/v1/tables/upsertRowCreate a row if no match found, or update existing row if match exists. Useful for sync operations.
Parameters
tableId | stringrequired | Table ID |
matchFieldId | stringrequired | Field ID to match on (must be unique or will update first match) |
matchValue | any | Value to match against |
data | objectrequired | Row data with field IDs as keys |
includeReadable | boolean | Include human-readable output |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/upsertRow \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"matchFieldId": "example",
"matchValue": {}
}'/api/v1/tables/getTableSchemaGet table structure/schema. Useful for understanding table layout before creating/updating rows.
Parameters
tableId | stringrequired | Table ID |
format | string | Output format: json (full), array (simple), markdown (documentation) |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getTableSchema \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"format": "example"
}'/api/v1/tables/duplicateTableClone a table with its structure (fields) and optionally data (rows) and views.
Parameters
tableId | stringrequired | Source table ID to duplicate |
newName | stringrequired | Name for the new table |
targetDatabaseId | string | Target database ID (defaults to same database) |
includeRows | boolean | Copy all rows from source table |
includeViews | boolean | Copy views configuration |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/duplicateTable \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"newName": "example",
"targetDatabaseId": "example"
}'/api/v1/tables/getHelpGet help for Tables API. Call with topic to get focused guidance.
Parameters
topic | string | Topic: "overview", "fields", "rows", "views", "linked", "buttons" |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getHelp \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"topic": "example"
}'/api/v1/tables/setAccessRulesSet access rules for a table. Controls who can create/read/update/delete rows in published apps. App owner always has full access.
Parameters
tableId | stringrequired | Table ID from listTables |
accessRules | objectrequired | Access rules per operation (create/read/update/delete). Each is a Condition: a single rule, a legacy flat array (OR), or an { all | any | not } group. Rule types: public, authenticated, creator, field_match, user_property (with op: eq/ne/gt/gte/lt/lte/in/nin/contains/isEmpty/isNotEmpty), has_role, email, function. AND/OR/NOT groups + operators enable any combination. |
trackCreator | boolean | Whether to track who creates each row. OMIT to keep the table's current setting — it used to default to true, so a call that only changed a read rule silently re-enabled creator tracking. |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/setAccessRules \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example",
"accessRules": {},
"trackCreator": true
}'/api/v1/tables/getAccessRulesGet access rules for a table
Parameters
tableId | stringrequired | Table ID from listTables |
Example Request
curl -X POST https://app.serenitiesai.com/api/v1/tables/getAccessRules \
-H "Authorization: Bearer mk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"tableId": "example"
}'