API · Endpoints

Rows

Read and write rows on a table surface. Single-row CRUD, atomic bulk ops up to 500 changes per call, cross-surface moves, and per-cell change history.

Generated from src/lib/api-paths/rows.ts. The body schemas come straight from CreateRowSchema, UpdateRowSchema, and MoveRowsSchema in the runtime, so what's documented here is what's enforced.

get/api/workspaces/{slug}/rows

List rows in a workspace

Returns rows from the workspace's primary table surface unless `?surface=<slug>` is passed. Newest-first by default.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes

Query parameters

NameTypeRequiredDescription
surfacestringnoSurface slug to scope to. Omit for the primary table surface.
limitstringnoPage size. Default 50, max 500.
offsetstringnoOffset-based pagination cursor.

Responses

StatusBodyDescription
200objectRow list with total count.
403ErrorForbidden.

post/api/workspaces/{slug}/rows

Create a row

Add a new row to a table surface. `data` keys must match column ids on the surface; values are coerced to the column type. Multi-surface workspaces accept `surface` (slug) or `surfaceId` to pick which sheet the row lands on; omit both to fall through to the workspace's primary table surface.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes

Request body

FieldTypeRequiredDescription
dataobjectyes
positionintegerno
auto_create_columnsbooleanno
surfaceIdstringno
surfacestringno
surface_slugstringno

Responses

StatusBodyDescription
200objectCreated.
400ErrorInvalid body.
402ErrorRow cap reached for the current plan.
403ErrorForbidden.

get/api/workspaces/{slug}/rows/{id}

Get a single row

Fetch one row by id, including its current cell values.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes
idstringyes

Responses

StatusBodyDescription
200objectRow detail.
404ErrorRow not found.

patch/api/workspaces/{slug}/rows/{id}

Update a row

Patch the `data` field on an existing row. Only the column keys you include get updated; other cells are left alone. Setting `surface` (slug) or `surfaceId` to a different sheet MOVES the row there: position recomputes to the destination's tail (override with `position`) and a `row.moved_surface` event fires. Same-surface is a no-op move.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes
idstringyes

Request body

FieldTypeRequiredDescription
dataobjectno
positionnumberno
auto_create_columnsbooleanno
surfaceIdstringno
surfacestringno
surface_slugstringno

Responses

StatusBodyDescription
200objectUpdated.

delete/api/workspaces/{slug}/rows/{id}

Delete a row

Permanent. No soft-delete on individual rows.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes
idstringyes

Responses

StatusBodyDescription
200objectDeleted.

post/api/workspaces/{slug}/rows/bulk

Bulk row operations

Atomic create + update + delete in a single request. Up to 500 ops per call. All ops apply in one Prisma transaction so partial-success scenarios don't happen.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes

Request body

FieldTypeRequiredDescription
createobject[]no
patchobject[]no
deletestring[]no

Responses

StatusBodyDescription
200objectBulk applied.

post/api/workspaces/{slug}/rows/move

Move rows to a different surface

Atomic batch move. All rows move to the target surface (specified by `surfaceId` or `surface` slug). Positions are recomputed at the destination tail.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes

Request body

FieldTypeRequiredDescription
rowIdsstring[]yes
surfaceIdstringno
surfacestringno
surface_slugstringno

Responses

StatusBodyDescription
200objectMoved.

get/api/workspaces/{slug}/rows/{id}/history

Row change history

Per-cell change history for one row. Returns chronological diffs with author + timestamp.

Auth: Bearer token (API key or OAuth access token).

Path parameters

NameTypeRequiredDescription
slugstringyes
idstringyes

Responses

StatusBodyDescription
200objectHistory entries.

Frequently asked questions

How do I append a row to a Dock table via the REST API?
POST `/api/workspaces/:slug/rows` with `{ data: { col1: val1, ... } }`. For multi-surface workspaces, pass `surface` (slug) or `surfaceId` to pick which sheet; omit to fall through to the workspace's primary table surface.
What happens if my row data has keys that don't match any column?
The keys are stored on the row's `data` JSON (nothing is dropped), but they won't render in the table UI until the column exists. The response surfaces them as `unmapped_fields: [...]` plus a human-readable `warning` so you can decide whether to call `add_column` or retry with `auto_create_columns: true`. Older clients see the same warning embedded in the row response.
Can the Dock rows API auto-create columns for unknown keys?
Yes, with explicit opt-in. POST/PATCH `/rows` with `{ data, auto_create_columns: true }`. When set, the server appends a `text` column (key + humanised label) for every key in `data` not already on the surface, then applies the row write atomically. Response payload then includes `created_columns: ColumnDef[]`. Off by default to keep typo pollution out of the schema (a stray `compamy` payload key shouldn't become a permanent column unless you ask). MCP `create_row` / `update_row` accept the same arg.
How do I list rows in a Dock workspace?
GET `/api/workspaces/:slug/rows`. Query params: `?limit=100&after=<cursor>&sort=title&surface=<slug>`. Default returns rows from every surface (back-compat); pass `surface` to scope.
How do I update a row in a Dock workspace?
PATCH `/api/workspaces/:slug/rows/:id` with `{ data: { col: newVal } }`. Partial-merge: only the keys you include are updated. Setting `surface` or `surfaceId` to a different sheet MOVES the row. Pass `auto_create_columns: true` to have the server promote any unknown keys to fresh text columns in the same call (default off).
How do I delete a row in a Dock workspace?
DELETE `/api/workspaces/:slug/rows/:id`. Hard-delete; not recoverable. Editor role required. Emits `row.deleted` event with full attribution.
How do I move many Dock rows to a different sheet at once?
POST `/api/workspaces/:slug/rows/move` (or MCP `move_rows`) with `{ rowIds, target_surface_slug }`. Atomic; all-or-nothing if any rowId doesn't belong to the workspace. Up to 500 rows per call. Idempotent on rows already on the target.
Does the Dock rows API return who created each row?
Yes. Every row response includes `createdBy: { principalType, id, name }` and `updatedBy` after edits. Pre-attribution rows show `null`. Use `principal.type === 'agent'` to filter agent-only writes.
How do I read rows from a specific surface in a multi-surface Dock workspace?
GET `/api/workspaces/:slug/rows?surface=<slug>` (or `?surfaceId=<id>`). Without the param, returns rows from every surface in the workspace (back-compat for single-sheet clients).
Does the Dock rows API support real-time updates?
Yes, via SSE on `GET /api/workspaces/:slug/stream` (subscribe to `row.created` / `row.updated` / `row.deleted` / `row.moved_surface` events). Or via webhooks for serverless / cron agents. Learn more →
What's the rate limit on Dock row writes?
Plan-tier-scoped against the org's monthly API call cap (Free 10K, Pro 100K, Scale 1M). Per-principal burst limits prevent monopolization. Hitting the cap returns 402 with actionable next-step recommendations. Learn more →
Can my Dock agent get notified when a row changes?
Yes. Register a webhook on `row.updated` (or `row.created` / `row.deleted` / `row.moved_surface`). The payload includes the changed row + `principal` block so the agent can route per-principal (e.g., react only to human edits).
Updated